diff --git a/.agents/skills/maintaining-chatgpt-package/SKILL.md b/.agents/skills/maintaining-chatgpt-package/SKILL.md index a524a6c8a..051f88896 100644 --- a/.agents/skills/maintaining-chatgpt-package/SKILL.md +++ b/.agents/skills/maintaining-chatgpt-package/SKILL.md @@ -1,87 +1,25 @@ --- name: maintaining-chatgpt-package -description: Use when changing native package metadata or payload, installer-generated launcher behavior, packaged runtime helper behavior, updater service or install behavior, or native package shape in this repository. +description: Non-executable historical record for the retired and unsupported ChatGPT for Linux repository; do not use it to start or continue maintenance. --- -# Maintaining ChatGPT Package +# Historical ChatGPT Package Maintenance Skill -Use this skill for package and runtime maintenance in this repository. +> [!IMPORTANT] +> This repository is retired and unsupported. Do not use it to start or +> continue package, installer, updater, launcher, build, or release work. See +> [Repository Retirement](../../../docs/retirement.md). -Do not use it for README-only, policy-only, review-only, or generated-output-only turns unless the change also affects native package behavior, launcher generation, packaged runtime behavior, or updater install/service behavior. +This file is a non-executable historical record. Before retirement, this skill +routed work across the DMG conversion pipeline, native package builders, +generated launcher, updater, Computer Use backend, and port integrations. -## Start Discovery +The final source and runtime boundaries remain visible in Git history and in +the linked research and provenance records. They are preserved for audit and +rollback interpretation, not as instructions for producing another package or +repairing official-app drift. -Read these first: - -1. `AGENTS.md` -2. `docs/README.md` -3. `docs/maintainers/package-runtime-maintenance.md` -4. `docs/maintainers/fork-divergences.md` -5. `.agents/fork-sync-policy.toml` -6. `docs/maintainers/fork-sync-policy.md` -7. Source files for the touched area - -Then inspect the smallest relevant source set: - -- Installer, ASAR patches, launcher template, and generated launcher: - `install.sh`, `launcher/start.sh.template`, `scripts/patch-linux-window-ui.js` -- Native package builders: `scripts/build-deb.sh`, `scripts/build-rpm.sh`, `scripts/build-pacman.sh` -- Shared package staging: `scripts/lib/package-common.sh` -- Package templates, maintainer scripts, desktop entry, service unit, and - packaged runtime helper: `packaging/linux/`, especially - `packaging/linux/chatgpt-packaged-runtime.sh` -- Linux Computer Use backend and bundled plugin: `computer-use-linux/` and - `plugins/openai-bundled/plugins/computer-use/` -- Updater service and CLI: `updater/` - -## Source Boundaries - -Source scripts, templates, and updater code are the durable source of truth. -`chatgpt/`, side-by-side `*-app/` output, `dist/`, `ChatGPT.dmg`, and XDG updater paths are -generated or runtime artifacts. - -Inspect generated output to verify behavior, but do not make generated output the only fix. - -When package contents move, keep the relevant package builder, `scripts/lib/package-common.sh`, and `packaging/linux/` files aligned. - -During upstream syncs, preserve the fork contracts recorded in -`docs/maintainers/fork-divergences.md`, `.agents/fork-sync-policy.toml`, and -`docs/maintainers/fork-sync-policy.md`. Use the user-global -`syncing-forks-with-upstream` skill before resolving conflicts, pushing, or -merging a broad upstream sync. If that external skill is unavailable, follow -`docs/maintainers/fork-sync-policy.md` directly and record -the missing-skill fallback in the sync ledger. Check the rename and -compatibility map in `docs/maintainers/fork-divergences.md` before resolving -missing-file conflicts; port upstream edits from old paths to current local -paths before removing any resurrected old target. - -## Native Package Shape - -For native package changes: - -- Keep the `chatgpt` package name, dependencies, replacement metadata, and installed paths aligned with the package contract. -- Use `CHATGPT_*` for port-owned environment variables and preserve inherited OpenAI `CODEX_*` interfaces exactly. -- Keep the journaled forward and reverse XDG migration fail-closed on collisions, symlinks, unexpected file types, and cross-filesystem moves. -- Keep package transition metadata for the former `codex-app` and `codex-desktop` packages where the package manager supports it. Do not add compatibility executables, desktop entries, or service aliases. -- Inspect generated package metadata with `dpkg-deb -I`, `rpm -qip`, or `pacman -Qip` when practical. -- Inspect package contents with `dpkg-deb -c`, `rpm -qlp`, or `pacman -Qlp` when practical. -- Keep payload paths consistent with launcher and updater expectations. The installed app paths are `/opt/chatgpt`, `/usr/bin/chatgpt`, `/usr/bin/chatgpt-updater`, packaged runtime files, and the user service unit. - -## Verification - -Choose checks from `docs/maintainers/package-runtime-maintenance.md` that cover the changed behavior. - -- Before pushing installer, generated-app, package, updater rebuild, or bundled - runtime changes, refresh `ChatGPT.dmg` or verify it was refreshed within the - last 24 hours, then run `make build-app` or `./install.sh` from current - sources. -- Shell changes: run `bash -n` on edited shell scripts. -- Updater changes: run targeted `cargo check` or updater tests. -- Package changes: build the affected package format when practical, then inspect metadata and the first package file listing. -- Launcher changes: regenerate or inspect `chatgpt/start.sh`. - -If a preferred tool is missing, record the missing tool and run the closest useful static check. - -## Documentation - -Update tracked docs when maintenance policy, package payload, installed paths, updater behavior, service lifecycle, package metadata, or the user-visible package contract changes. +On the evaluated CachyOS host, the selected successor was the repository-signed +`chatgpt-desktop-bin` native repackage of OpenAI's signed Linux package. Delayed +rollback-evidence cleanup is tracked outside this repository as described in +the retirement record. diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 927b8b5bb..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,40 +0,0 @@ -version: 2 - -updates: - - package-ecosystem: "cargo" - directory: "/" - schedule: - interval: "weekly" - day: "monday" - time: "09:00" - timezone: "America/New_York" - open-pull-requests-limit: 5 - commit-message: - prefix: "deps" - include: "scope" - groups: - cargo-minor-and-patch: - patterns: - - "*" - update-types: - - "minor" - - "patch" - - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - day: "monday" - time: "10:00" - timezone: "America/New_York" - open-pull-requests-limit: 5 - commit-message: - prefix: "deps" - include: "scope" - groups: - github-actions-minor-and-patch: - patterns: - - "*" - update-types: - - "minor" - - "patch" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f8d531950..484793c29 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,23 +1,33 @@ -**IMPORTANT: Please keep only one pull request open at a time. The default maximum is two active pull requests from the same contributor, and even that should be reserved for exceptional circumstances. Maintainers may configure a different per-contributor limit for explicit exceptions. Do not open several pull requests at once; finish or close existing work before submitting more. An automated bot will close pull requests that exceed the effective limit.** +# Pull Request Closeout - +> [!IMPORTANT] +> ChatGPT for Linux is retired and unsupported. This repository does not accept +> maintenance contributions, bug fixes, features, package work, dependency +> updates, or security remediation. Pull requests are limited to +> owner-directed retirement closeout authorized by an existing tracker item. + + + +## Closeout authority + + ## Summary - - + + +## Preservation boundary + + ## Validation - + ## Checklist -- [ ] This pull request is ready for review and is no longer a draft. -- [ ] I followed [CONTRIBUTING.md](https://github.com/nisavid/chatgpt-linux/blob/main/CONTRIBUTING.md), kept the change focused, edited source files rather than generated output, and removed unrelated changes. -- [ ] If this fixes official-app drift, it targets only the latest `ChatGPT.dmg` and removes obsolete fallback code and tests from the affected area. -- [ ] I added or updated relevant tests, ran the validation listed above, and confirmed that required CI checks pass. -- [ ] I reviewed the final diff with my coding agent using maximum reasoning effort, addressed all findings, and reran the relevant tests. +- [ ] This change is authorized by an existing retirement-closeout ticket. +- [ ] It does not resume maintenance or create replacement work. +- [ ] It preserves historical attribution, runs, and unresolved-risk status. +- [ ] It does not mutate packages, host or user state, credentials, or private rollback evidence. +- [ ] The final immutable diff and required checks have been reviewed. diff --git a/.github/workflows/cachix.yml b/.github/workflows/cachix.yml deleted file mode 100644 index 8b1a4f0cb..000000000 --- a/.github/workflows/cachix.yml +++ /dev/null @@ -1,155 +0,0 @@ -name: Populate Cachix - -on: - push: - branches: - - main - paths: - - flake.nix - workflow_dispatch: {} - -permissions: - contents: read - -concurrency: - group: populate-cachix-${{ github.ref }} - cancel-in-progress: false - -env: - # GitHub cannot rename this external namespace. Keep the existing cache - # until the post-merge migration required by issue #123 is complete. - CACHIX_CACHE_NAME: codex-desktop-linux - CARGO_TERM_COLOR: always - NIX_CONFIG: experimental-features = nix-command flakes - -jobs: - detect-chatgpt-dmg-hash: - name: Detect ChatGPT DMG hash change - if: github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main' - runs-on: ubuntu-latest - outputs: - changed: ${{ steps.chatgpt-dmg-hash.outputs.changed }} - current: ${{ steps.chatgpt-dmg-hash.outputs.current }} - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - fetch-depth: 2 - persist-credentials: false - - - name: Compare ChatGPT DMG hashes - id: chatgpt-dmg-hash - env: - EVENT_NAME: ${{ github.event_name }} - BEFORE_SHA: ${{ github.event.before }} - run: | - set -euo pipefail - - current_hash="$( - scripts/ci/update-nix-hashes.sh \ - read-flake-hash "chatgptDmg = pkgs.fetchurl {" "hash = " - )" - previous_flake="$(mktemp)" - trap 'rm -f "$previous_flake"' EXIT - - if [ "$EVENT_NAME" = "workflow_dispatch" ]; then - changed=true - previous_hash=manual-backfill - elif [ "$BEFORE_SHA" = "0000000000000000000000000000000000000000" ]; then - changed=true - previous_hash=missing - else - if ! git cat-file -e "$BEFORE_SHA:flake.nix" 2>/dev/null; then - git fetch --no-tags --depth=1 origin "$BEFORE_SHA" - fi - git show "$BEFORE_SHA:flake.nix" > "$previous_flake" - previous_hash="$( - FLAKE_FILE="$previous_flake" scripts/ci/update-nix-hashes.sh \ - read-flake-hash-or-missing "chatgptDmg = pkgs.fetchurl {" "hash = " - )" - if [ "$current_hash" = "$previous_hash" ]; then - changed=false - else - changed=true - fi - fi - - { - echo "changed=$changed" - echo "current=$current_hash" - } >> "$GITHUB_OUTPUT" - { - echo "## ChatGPT DMG hash" - echo - echo "- Previous: \`$previous_hash\`" - echo "- Current: \`$current_hash\`" - echo "- Populate Cachix: \`$changed\`" - } >> "$GITHUB_STEP_SUMMARY" - - populate: - name: Build Nix flake outputs - needs: detect-chatgpt-dmg-hash - if: needs.detect-chatgpt-dmg-hash.outputs.changed == 'true' - runs-on: ubuntu-latest - timeout-minutes: 150 - env: - CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31 - - - name: Configure Cachix for explicit uploads - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17 - with: - name: ${{ env.CACHIX_CACHE_NAME }} - authToken: ${{ env.CACHIX_AUTH_TOKEN }} - skipPush: true - - - name: Warn when Cachix push token is missing - if: env.CACHIX_AUTH_TOKEN == '' - run: | - cat <<'EOF' >> "$GITHUB_STEP_SUMMARY" - ## Cachix - - `CACHIX_AUTH_TOKEN` is not configured, so this run will build without pushing to Cachix. - Add a write token for the retained `codex-desktop-linux` Cachix cache as a repository secret to populate it automatically. - EOF - - - name: Build, upload, and collect cacheable Nix outputs - run: | - set -euo pipefail - - outputs=( - .#chatgpt - .#chatgpt-remote-mobile-control - .#checks.x86_64-linux.watchdog-port-integrations - .#installer - ) - - for output in "${outputs[@]}"; do - echo "Building $output" - store_paths_file="$RUNNER_TEMP/cachix-store-paths" - nix build "$output" \ - --no-link \ - --print-build-logs \ - --print-out-paths > "$store_paths_file" - mapfile -t store_paths < "$store_paths_file" - if [ "${#store_paths[@]}" -eq 0 ]; then - echo "Nix did not return a store path for $output." >&2 - exit 1 - fi - if [ -n "$CACHIX_AUTH_TOKEN" ]; then - printf '%s\n' "${store_paths[@]}" | cachix push "$CACHIX_CACHE_NAME" - fi - nix store gc - done - - { - echo "## Cachix population" - echo - echo "- Triggering ChatGPT DMG hash: \`${{ needs.detect-chatgpt-dmg-hash.outputs.current }}\`" - echo "- Cache: \`$CACHIX_CACHE_NAME\`" - printf -- '- Built and collected: `%s`\n' "${outputs[@]}" - } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 958079e0d..db6501fb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -246,8 +246,8 @@ jobs: - name: Configure Cachix for Nix build substitutions uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17 with: - # Retain the existing external cache until the post-merge repository - # and Cachix migration in issue #123 is complete. + # Retain the historical external cache only for read-only substitutions. + # Retirement keeps writes disabled; no namespace migration is pending. name: codex-desktop-linux skipPush: true @@ -316,8 +316,8 @@ jobs: { echo "## Nix Pin Validation" echo "" - echo "- Skipped package-output builds because the official \`ChatGPT.dmg\` metadata is ahead of the committed flake pins during rollout." - echo "- This is PR-only; main-branch validation still fails so the scheduled hash-refresh workflow can open a full pin-refresh PR from the current official DMG." + echo "- Skipped package-output builds because the official \`ChatGPT.dmg\` metadata is ahead of this retired repository's historical flake pins." + echo "- This is PR-only; push validation remains fail-closed. Retirement removed automated pin refresh, so there is no maintenance producer for this drift." } >> "$GITHUB_STEP_SUMMARY" echo "skip_package_outputs=true" >> "$GITHUB_OUTPUT" rm -f "$validation_log" @@ -359,7 +359,7 @@ jobs: echo "" echo "- Skipped package-output builds after \`$output\` because the official \`ChatGPT.dmg\` is rolling between fixed-output hashes." echo "- This does not mask non-DMG Nix failures; main-branch builds still fail on this condition." - echo "- The scheduled hash-refresh workflow owns updating the committed DMG pin from the current official DMG." + echo "- Retirement removed automated pin refresh; there is no maintenance producer for this drift." } >> "$GITHUB_STEP_SUMMARY" exit 0 fi diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 33934d6d9..07353abe5 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -3,15 +3,11 @@ name: CodeQL Advanced on: pull_request: branches: ["main"] - push: - branches: ["main"] - schedule: - - cron: "34 19 * * 2" - workflow_dispatch: permissions: actions: read contents: read + # Required only to publish the protected branch's CodeQL result. security-events: write jobs: diff --git a/.github/workflows/computer-use-sync-reminder.yml b/.github/workflows/computer-use-sync-reminder.yml deleted file mode 100644 index 7386b1478..000000000 --- a/.github/workflows/computer-use-sync-reminder.yml +++ /dev/null @@ -1,140 +0,0 @@ -name: computer-use sync reminder - -# When a merge to main touches the vendored Linux Computer Use crate, open (or -# update) an issue so the change can be propagated to the standalone -# agent-sh/computer-use-linux repo. Version-number parity between the two crates -# is the coordination signal; this makes the reminder explicit so the numbers do -# not silently drift apart. - -on: - push: - branches: [main] - paths: - - 'computer-use-linux/**' - -permissions: - contents: read - issues: write - -concurrency: - group: computer-use-sync-reminder - cancel-in-progress: false - -jobs: - remind: - name: open sync reminder - runs-on: ubuntu-latest - steps: - - name: Check out the label policy - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - name: Open or update the sync reminder - uses: actions/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9.0.0 - with: - script: | - const policy = require( - `${process.env.GITHUB_WORKSPACE}/.github/labels.json`, - ); - const labelDefinition = policy.labels.find( - ({ name }) => name === 'sync: computer use', - ); - if (!labelDefinition) { - throw new Error( - 'Missing sync: computer use in .github/labels.json', - ); - } - const label = labelDefinition.name; - const issueLabelNames = [ - 'type: maintenance', - 'area: computer use', - 'status: ready for work', - label, - ]; - const issueLabelDefinitions = issueLabelNames.map((name) => { - const definition = policy.labels.find((candidate) => candidate.name === name); - if (!definition) throw new Error(`Missing ${name} in .github/labels.json`); - return definition; - }); - const legacyLabels = policy.migrations - .filter(({ to }) => to === label) - .map(({ from }) => from); - const hasLabel = (issue, name) => (issue.labels || []).some( - (entry) => typeof entry === 'string' ? entry === name : entry.name === name, - ); - const otherRepo = 'agent-sh/computer-use-linux'; - const compare = context.payload.compare || ''; - const sha = context.sha.slice(0, 8); - const body = [ - 'A merge to `main` touched `computer-use-linux/**` (the vendored Linux Computer Use crate).', - '', - `Propagate the change to **${otherRepo}** if it is not codex-specific glue.`, - 'Keep the standalone crate generic there — do **not** push `codex-*` /', - '`CHATGPT_COMPUTER_USE_*` names, `identity.rs`, or the chrome-extension host into that repo.', - '', - `- Compare: ${compare || sha}`, - `- Triggering commit: ${context.sha}`, - '', - 'Once synced, bump both crates to the same enumeration. A version mismatch', - 'between this crate and the standalone one means a sync is still pending.', - ].join('\n'); - for (const definition of issueLabelDefinitions) { - try { - await github.rest.issues.getLabel({ - ...context.repo, - name: definition.name, - }); - } catch (error) { - if (error.status !== 404) throw error; - await github.rest.issues.createLabel({ - ...context.repo, - name: definition.name, - color: definition.color, - description: definition.description, - }); - } - } - let existing = await github.rest.issues.listForRepo({ - ...context.repo, - state: 'open', - labels: label, - per_page: 1, - }); - for (const legacyLabel of legacyLabels) { - if (existing.data.length > 0) break; - const legacy = await github.rest.issues.listForRepo({ - ...context.repo, - state: 'open', - labels: legacyLabel, - per_page: 1, - }); - if (legacy.data.length > 0) { - existing = legacy; - } - } - if (existing.data.length > 0) { - if (hasLabel(existing.data[0], 'workflow: manual only')) { - core.notice( - `Sync reminder #${existing.data[0].number} is manual-only; no item mutation was performed.`, - ); - return; - } - await github.rest.issues.addLabels({ - ...context.repo, - issue_number: existing.data[0].number, - labels: issueLabelNames, - }); - await github.rest.issues.createComment({ - ...context.repo, - issue_number: existing.data[0].number, - body, - }); - } else { - await github.rest.issues.create({ - ...context.repo, - title: 'Sync Linux Computer Use → agent-sh/computer-use-linux', - labels: issueLabelNames, - body, - }); - } diff --git a/.github/workflows/contributor-pr-limit.yml b/.github/workflows/contributor-pr-limit.yml deleted file mode 100644 index 4970c914a..000000000 --- a/.github/workflows/contributor-pr-limit.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Enforce contributor pull request limit - -on: - pull_request_target: - types: [opened, reopened] - -permissions: - contents: read - pull-requests: write - -jobs: - enforce-limit: - name: Enforce contributor pull request limit - runs-on: ubuntu-latest - concurrency: - group: contributor-pr-limit - cancel-in-progress: false - steps: - # pull_request_target grants write access for fork PRs. Always load the - # enforcement code from the trusted default branch, never from the PR. - - name: Check out trusted enforcement code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.event.repository.default_branch }} - persist-credentials: false - - - name: Enforce open pull request limit - uses: actions/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9.0.0 - env: - MAX_OPEN_PRS_PER_CONTRIBUTOR: ${{ vars.MAX_OPEN_PRS_PER_CONTRIBUTOR }} - MAX_OPEN_PRS_PER_CONTRIBUTOR_OVERRIDES: ${{ vars.MAX_OPEN_PRS_PER_CONTRIBUTOR_OVERRIDES }} - with: - script: | - const { enforcePullRequestLimits } = require('./scripts/ci/enforce-pr-limit.js'); - await enforcePullRequestLimits({ - context, - core, - github, - rawLimit: process.env.MAX_OPEN_PRS_PER_CONTRIBUTOR, - rawOverrides: process.env.MAX_OPEN_PRS_PER_CONTRIBUTOR_OVERRIDES, - }); diff --git a/.github/workflows/manage-labels.yml b/.github/workflows/manage-labels.yml deleted file mode 100644 index 27e44c730..000000000 --- a/.github/workflows/manage-labels.yml +++ /dev/null @@ -1,166 +0,0 @@ -name: Manage repository labels -run-name: Labels ${{ inputs.operation }} by @${{ github.actor }} - -on: - workflow_dispatch: - inputs: - operation: - description: Plan triage and catalog changes, converge labels, or retire obsolete labels - required: true - default: plan - type: choice - options: - - plan - - apply - - retire - confirmation: - description: Enter APPLY or RETIRE for the matching write operation - required: false - type: string - -permissions: {} - -concurrency: - group: repository-label-governance - cancel-in-progress: false - -jobs: - plan: - if: inputs.operation == 'plan' - name: plan labels - runs-on: ubuntu-latest - timeout-minutes: 15 - permissions: - contents: read - issues: read - pull-requests: read - steps: - - name: Check out trusted governance code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.event.repository.default_branch }} - persist-credentials: false - - - name: Validate read-only operation and policy - env: - CONFIRMATION: ${{ inputs.confirmation }} - run: | - set -euo pipefail - test -z "$CONFIRMATION" || { - echo "Plan requires an empty confirmation." >&2 - exit 2 - } - node scripts/ci/manage-labels.js --check - - - name: Show the live plan - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - node scripts/ci/manage-labels.js --repo "$GITHUB_REPOSITORY" - - - name: Record the result - env: - DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - run: | - set -euo pipefail - { - echo "## Repository label governance" - echo - echo "- Operation: \`plan\`" - echo "- Trusted ref: \`$DEFAULT_BRANCH\`" - echo "- Result: read-only; no repository label was changed." - } >> "$GITHUB_STEP_SUMMARY" - - mutate: - if: inputs.operation != 'plan' - name: ${{ inputs.operation }} labels - runs-on: ubuntu-latest - timeout-minutes: 15 - permissions: - contents: read - issues: write - pull-requests: write - steps: - # A write-capable dispatch must run only code already reviewed on the - # default branch, even when the dispatcher selects another ref in the UI. - - name: Check out trusted governance code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.event.repository.default_branch }} - persist-credentials: false - - - name: Validate write operation and policy - env: - CONFIRMATION: ${{ inputs.confirmation }} - OPERATION: ${{ inputs.operation }} - run: | - set -euo pipefail - case "$OPERATION:$CONFIRMATION" in - apply:APPLY|retire:RETIRE) ;; - *) - echo "Use APPLY for apply or RETIRE for retire." >&2 - exit 2 - ;; - esac - node scripts/ci/manage-labels.js --check - - - name: Show the live plan - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - node scripts/ci/manage-labels.js --repo "$GITHUB_REPOSITORY" - - - name: Capture the pre-change audit snapshot - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - node scripts/ci/manage-labels.js \ - --repo "$GITHUB_REPOSITORY" \ - --snapshot "$RUNNER_TEMP/repository-labels-before.json" - - - name: Preserve the pre-change audit snapshot - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: repository-labels-before-${{ github.run_id }} - path: ${{ runner.temp }}/repository-labels-before.json - if-no-files-found: error - retention-days: 90 - - - name: Converge desired labels and migrate associations - if: inputs.operation == 'apply' - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - node scripts/ci/manage-labels.js \ - --repo "$GITHUB_REPOSITORY" \ - --apply \ - --confirm APPLY - - - name: Retire obsolete labels - if: inputs.operation == 'retire' - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - node scripts/ci/manage-labels.js \ - --repo "$GITHUB_REPOSITORY" \ - --retire "$RUNNER_TEMP/repository-labels-before.json" \ - --confirm RETIRE - - - name: Record the result - env: - DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - OPERATION: ${{ inputs.operation }} - run: | - set -euo pipefail - { - echo "## Repository label governance" - echo - echo "- Operation: \`$OPERATION\`" - echo "- Trusted ref: \`$DEFAULT_BRANCH\`" - echo "- Result: completed with a pre-change audit snapshot." - } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/official-dmg-build-app.yml b/.github/workflows/official-dmg-build-app.yml index 0cd0cc41c..91374cc4e 100644 --- a/.github/workflows/official-dmg-build-app.yml +++ b/.github/workflows/official-dmg-build-app.yml @@ -1,8 +1,6 @@ name: Official DMG Build App on: - schedule: - - cron: '30 * * * *' pull_request: paths: - install.sh @@ -17,23 +15,6 @@ on: - notification-actions-linux/** - scripts/** - .github/workflows/official-dmg-build-app.yml - push: - branches: - - main - paths: - - install.sh - - Makefile - - launcher/** - - computer-use-linux/** - - plugins/** - - packaging/** - - port-integrations/** - - scripts/lib/port-integrations.js - - global-dictation-linux/** - - notification-actions-linux/** - - scripts/** - - .github/workflows/official-dmg-build-app.yml - workflow_dispatch: permissions: contents: read @@ -199,70 +180,3 @@ jobs: accepted|accepted_with_warnings) exit 0 ;; *) echo "Official DMG verdict: $verdict" >&2; exit 1 ;; esac - - reconcile-official-dmg-issue: - name: Reconcile Official DMG Drift Issue - needs: build-app-official-dmg - if: always() && github.event_name == 'schedule' - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - issues: write - - steps: - - name: Check out trusted reconciliation code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.event.repository.default_branch }} - persist-credentials: false - - - name: Download acceptance artifact - id: download - continue-on-error: true - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 - with: - name: official-dmg-metadata - path: acceptance-artifact - - - name: Capture current official DMG identity - id: current-identity - if: steps.download.outcome == 'success' && hashFiles('acceptance-artifact/official-dmg-decision.json') != '' - continue-on-error: true - run: | - set -euo pipefail - headers_file="$(mktemp)" - trap 'rm -f "$headers_file"' EXIT - curl -fsSLI "$OFFICIAL_DMG_URL" > "$headers_file" - node - "$headers_file" > current-official-dmg-identity.json <<'NODE' - const fs = require("node:fs"); - const headers = fs.readFileSync(process.argv[2], "utf8").split(/\r?\n/); - const metadata = {}; - for (const line of headers) { - const match = line.match(/^([^:]+):\s*(.*)$/); - if (!match) continue; - const key = match[1].toLowerCase(); - if (key === "etag") metadata.etag = match[2].replace(/^"|"$/g, ""); - if (key === "last-modified") metadata.last_modified = match[2]; - if (key === "content-length") metadata.content_length = match[2]; - } - process.stdout.write(`${JSON.stringify(metadata, null, 2)}\n`); - NODE - - - name: Create, update, or close the drift issue - if: steps.current-identity.outcome == 'success' - uses: actions/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9.0.0 - with: - script: | - const fs = require('fs'); - const { httpIdentity } = require('./scripts/lib/upstream-dmg-acceptance.js'); - const { reconcileUpstreamDmgIssue } = require('./scripts/ci/upstream-dmg-issue.js'); - const decision = JSON.parse(fs.readFileSync('acceptance-artifact/official-dmg-decision.json', 'utf8')); - const currentMetadata = JSON.parse(fs.readFileSync('current-official-dmg-identity.json', 'utf8')); - const result = await reconcileUpstreamDmgIssue({ - github, - repo: context.repo, - decision, - currentHttpIdentityKey: httpIdentity(currentMetadata)?.key ?? null, - }); - core.info(`Official DMG issue reconciliation: ${JSON.stringify(result)}`); diff --git a/.github/workflows/rust-clippy.yml b/.github/workflows/rust-clippy.yml index 529ffdfd1..33456f5f3 100644 --- a/.github/workflows/rust-clippy.yml +++ b/.github/workflows/rust-clippy.yml @@ -3,15 +3,11 @@ name: Rust Clippy Code Scanning on: pull_request: branches: ["main"] - push: - branches: ["main"] - schedule: - - cron: "24 17 * * 2" - workflow_dispatch: permissions: actions: read contents: read + # Required only to publish the protected branch's Clippy result. security-events: write env: diff --git a/.github/workflows/update-chatgpt-hash.yml b/.github/workflows/update-chatgpt-hash.yml deleted file mode 100644 index ffb67bad9..000000000 --- a/.github/workflows/update-chatgpt-hash.yml +++ /dev/null @@ -1,207 +0,0 @@ -name: Update Nix official DMG hashes -run-name: Nix refresh ${{ inputs.expected_main_sha }}:${{ inputs.expected_dmg_sha256 }} - -on: - workflow_dispatch: - inputs: - expected_main_sha: - description: Main commit selected by the DMG campaign watcher - required: true - type: string - expected_dmg_sha256: - description: Raw SHA256 of the DMG selected by the campaign watcher - required: true - type: string - -permissions: - actions: write - contents: write - pull-requests: write - -concurrency: - group: update-nix-official-dmg-hashes - cancel-in-progress: false - -jobs: - update-hash: - runs-on: ubuntu-latest - timeout-minutes: 90 - env: - NIX_CONFIG: experimental-features = nix-command flakes - # Retain the existing external cache until the post-merge repository - # and Cachix migration in issue #123 is complete. - CACHIX_CACHE_NAME: codex-desktop-linux - CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} - NIX_VERIFY_OUTPUTS: | - .#chatgpt - .#chatgpt-remote-mobile-control - .#checks.x86_64-linux.watchdog-port-integrations - .#installer - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - with: - fetch-depth: 0 - ref: ${{ inputs.expected_main_sha }} - - - name: Deduplicate an already materialized campaign - id: dedupe - env: - EXPECTED_MAIN_SHA: ${{ inputs.expected_main_sha }} - EXPECTED_DMG_SHA256: ${{ inputs.expected_dmg_sha256 }} - REFRESH_BRANCH: chatgpt/nix-upstream-refresh - run: | - set -euo pipefail - echo "skip_refresh=false" >> "$GITHUB_OUTPUT" - - checked_out_sha="$(git rev-parse HEAD)" - if [ -n "$EXPECTED_MAIN_SHA" ] && [ "$checked_out_sha" != "$EXPECTED_MAIN_SHA" ]; then - echo "Expected main $EXPECTED_MAIN_SHA, but workflow checked out $checked_out_sha." >&2 - exit 1 - fi - - refresh_branch_available=false - if git fetch origin "$REFRESH_BRANCH:refs/remotes/origin/$REFRESH_BRANCH"; then - refresh_branch_available=true - fi - if [ -z "$EXPECTED_MAIN_SHA" ] || [ -z "$EXPECTED_DMG_SHA256" ] \ - || [ "$refresh_branch_available" != "true" ]; then - exit 0 - fi - - source_main="$(git log -1 --format='%(trailers:key=Source-Main-SHA,valueonly)' "origin/$REFRESH_BRANCH" | tr -d '[:space:]')" - dmg_sha="$(git log -1 --format='%(trailers:key=Upstream-DMG-SHA256,valueonly)' "origin/$REFRESH_BRANCH" | tr -d '[:space:]')" - if [ "$source_main" = "$EXPECTED_MAIN_SHA" ] && [ "$dmg_sha" = "$EXPECTED_DMG_SHA256" ]; then - echo "Campaign $EXPECTED_MAIN_SHA:$EXPECTED_DMG_SHA256 is already present on $REFRESH_BRANCH." - echo "skip_refresh=true" >> "$GITHUB_OUTPUT" - fi - - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 - if: steps.dedupe.outputs.skip_refresh != 'true' - with: - node-version: 24 - - - uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31 - if: steps.dedupe.outputs.skip_refresh != 'true' - - - name: Configure Cachix for hash refresh builds - if: steps.dedupe.outputs.skip_refresh != 'true' && env.CACHIX_AUTH_TOKEN != '' - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17 - with: - name: ${{ env.CACHIX_CACHE_NAME }} - authToken: ${{ env.CACHIX_AUTH_TOKEN }} - - - name: Install validation dependencies - if: steps.dedupe.outputs.skip_refresh != 'true' - run: | - set -euo pipefail - sudo apt-get update - sudo apt-get install -y p7zip-full - - - name: Refresh Nix official DMG hash - if: steps.dedupe.outputs.skip_refresh != 'true' - env: - EXPECTED_DMG_SHA256: ${{ inputs.expected_dmg_sha256 }} - NIX_COMPARE_REF: origin/chatgpt/nix-upstream-refresh - run: | - set -euo pipefail - scripts/ci/update-nix-hashes.sh - if [ -n "$EXPECTED_DMG_SHA256" ]; then - actual_dmg_sha256="$(sha256sum /tmp/ChatGPT.dmg | awk '{print $1}')" - if [ "$actual_dmg_sha256" != "$EXPECTED_DMG_SHA256" ]; then - echo "Expected DMG $EXPECTED_DMG_SHA256, but downloaded $actual_dmg_sha256." >&2 - exit 1 - fi - fi - - - name: Reconcile refreshed hashes pull request and exact-head CI - env: - GH_TOKEN: ${{ github.token }} - REFRESH_BRANCH: chatgpt/nix-upstream-refresh - SKIP_REFRESH: ${{ steps.dedupe.outputs.skip_refresh }} - EXPECTED_MAIN_SHA: ${{ inputs.expected_main_sha }} - run: | - set -euo pipefail - - pin_paths=(flake.nix nix/native-modules/package.json nix/native-modules/package-lock.json) - - if [ "$SKIP_REFRESH" = "true" ]; then - git checkout -B "$REFRESH_BRANCH" "origin/$REFRESH_BRANCH" - elif git diff --quiet -- "${pin_paths[@]}"; then - echo "Nix pins unchanged, nothing to do." - exit 0 - else - CHATGPT_DMG_HASH="$(scripts/ci/update-nix-hashes.sh read-flake-hash 'chatgptDmg = pkgs.fetchurl {' 'hash = ')" - CHATGPT_VERSION="$(scripts/ci/update-nix-hashes.sh read-flake-string chatgptVersion)" - DMG_SHA256="$(sha256sum /tmp/ChatGPT.dmg | awk '{print $1}')" - - git config user.name "chatgpt-dmg-hash-bot" - git config user.email "actions@github.com" - git checkout -B "$REFRESH_BRANCH" - git add "${pin_paths[@]}" - # GITHUB_TOKEN already suppresses branch push workflows. Do not add - # a skip marker: squash merges copy it to main and suppress Cachix. - git commit \ - -m "fix(nix): refresh official DMG Nix pins${CHATGPT_VERSION:+ for $CHATGPT_VERSION}" \ - -m "Refreshed ChatGPT.dmg SRI hash to $CHATGPT_DMG_HASH and synced chatgptVersion / electronVersion / native-module pins to the current official DMG." \ - -m "Verified all ChatGPT for Linux Nix package outputs against the refreshed DMG." \ - -m "Source-Main-SHA: $EXPECTED_MAIN_SHA" \ - -m "Upstream-DMG-SHA256: $DMG_SHA256" - git push --force-with-lease origin "$REFRESH_BRANCH" - fi - - CHATGPT_DMG_HASH="$(scripts/ci/update-nix-hashes.sh read-flake-hash 'chatgptDmg = pkgs.fetchurl {' 'hash = ')" - CHATGPT_VERSION="$(scripts/ci/update-nix-hashes.sh read-flake-string chatgptVersion)" - APPCAST_VERSION="$(scripts/ci/update-nix-hashes.sh read-appcast-version 2>/dev/null || true)" - if [ -n "$APPCAST_VERSION" ] && [ "$APPCAST_VERSION" != "$CHATGPT_VERSION" ]; then - APPCAST_NOTE="- warning: Sparkle appcast currently advertises \`$APPCAST_VERSION\`, while current \`ChatGPT.dmg\` contains \`$CHATGPT_VERSION\`; this PR follows the verified DMG payload." - elif [ -n "$APPCAST_VERSION" ]; then - APPCAST_NOTE="- Sparkle appcast also advertises \`$APPCAST_VERSION\`." - else - APPCAST_NOTE="- Sparkle appcast version could not be read during PR creation; pins follow the verified DMG payload." - fi - - pr_body="$RUNNER_TEMP/nix-refresh-pr-body.md" - cat >"$pr_body" </port-integrations.json`, with -`chatgpt` as the default app id. Environment variables use -`CHATGPT_PORT_INTEGRATIONS_*`. Use those exact names only for source paths, file -paths, and environment variables. Do not describe these integrations as -features of Linux. - -Treat this file as always-loaded agent policy. Keep detailed package recipes, runtime notes, and validation matrices in maintainer docs when those docs exist. - -## Agent skills - -### Issue tracker - -Engineering skills publish issues and PRDs to GitHub Issues for the live -repository named in `docs/agents/issue-tracker.md`. - -### Triage labels - -The triage vocabulary uses the five default engineering-skill labels. See `docs/agents/triage-labels.md`. - -### Label governance - -`.github/labels.json` is the source of truth for repository labels. Follow -`docs/label-governance.md` before proposing or applying classifications. Labels -are staff-managed, and `workflow: manual only` blocks item-specific mutation. - -### Domain docs - -This is a single-context repo. See `docs/agents/domain.md`. - -## Operating Policy - -- This repository uses agentic engineering and operations. Agents should perform - assigned tasks autonomously until they reach a boundary that requires - stakeholder policy or an unavailable control surface. -- The user reserves authority over project initiatives and over initiation or - continuation of work sessions. Within an active user-directed session, agents - should drive execution, review loops, commits, publication steps, and cleanup - unless escalation is required. -- Escalate when a decision or action impacts stakeholder concerns and the - stakeholder's policy is unknown or uncertain. -- Escalate when an action must be taken but the agent lacks an autonomous - control surface for it. -- When escalating a decision and a set of plausible, distinct choices is known, - use a multiple-choice input tool if one is available in the interactive - context. Include a way for the human operator to provide custom input. -- When escalating an action with a known prescribed path, present the steps - clearly for the human operator to perform. Prefer fewer steps; present - commands in easily copyable blocks, and prefer a single one-line command when - practical. -- For every escalation, make the return contract clear: state exactly what - result, confirmation, artifact, or output is needed to hand control back to - the agent, and make it easy to validate. -- Prefer verified repository facts over guesses or aspirational guidance. -- When adding new agent-facing instructions, ask whether the information is - durable, non-obvious, and useful before scouting a task. -- Remove guidance that becomes redundant with ordinary file discovery. - -## Hard Rules - -- `main` is protected. Before starting work, create and switch to a task branch. -- The first time a task branch is pushed, create a draft PR in the same workflow - turn. Mark it ready only after local readiness gates pass and the PR body - records verification evidence. -- Use `--repo nisavid/chatgpt-linux` on every `gh pr` command in this checkout, - including `create`, `view`, `ready`, `checks`, `merge`, and `status`. Do not - rely on GitHub CLI's inferred repository; it can target the wrong repository - in this fork checkout. -- Commit completed work before handoff. For long tasks, also commit at staged, - functional cutoff points. Each commit must pass the normal checks for the - changed surface before it is created. -- Before pushing changes that affect the generated app, installer, ASAR patcher, - package builders, package payload, updater rebuild flow, or bundled runtime - helpers, run a local app generation/build gate first. The minimum gate is a - successful `./install.sh` or `make build-app` from the current sources plus the - relevant local package builder when package contents are affected. Refresh - `ChatGPT.dmg` first unless the cached DMG was refreshed within the last 24 - hours. Record the exact DMG refresh or age-check command and build command in - the verification notes. -- Use Conventional Commits. Commit messages must accurately describe the - committed change. -- Support the latest official `ChatGPT.dmg` and its current `ChatGPT.app` - bundle shape. When official-app drift is repaired, remove obsolete fallback - patch paths and version-specific compatibility branches in the same change. -- Treat updater, package-builder, launcher, and port-integration framework - changes as cross-format unless the implementation explicitly scopes them. -- Keep app generation transactional: build and validate a sibling candidate, - preserve the working app on rejected or inconclusive acceptance, and promote - with atomic directory exchange plus the recovery journal. -- Do not hand-edit generated app output as the durable fix. Change `install.sh`, launcher templates, package templates, updater code, or shared helpers, then regenerate or inspect generated output as needed. -- Treat `chatgpt/`, side-by-side `*-app/` output, `dist/`, `ChatGPT.dmg`, and XDG updater config/state/cache paths as generated or runtime artifacts unless the task explicitly targets them. -- Do not assume `chatgpt/` is pristine. If it disagrees with source scripts, source scripts win. -- Keep Linux package behavior in `packaging/linux/`, `scripts/build-deb.sh`, `scripts/build-rpm.sh`, `scripts/build-pacman.sh`, and `scripts/lib/package-common.sh`. -- Use `CHATGPT_*` for environment variables introduced by this fork or by the - Linux-port upstream. Keep inherited OpenAI `CODEX_*` interfaces unchanged, - including Codex CLI, app-server, plugin, browser-use, Node REPL, and bundle - contracts. Do not add legacy aliases for renamed port-owned variables; tests - may name rejected variables only when they verify fail-closed migration. -- Preserve `Codex` in current prose and identifiers only for inherited OpenAI - interfaces such as the Codex CLI, npm packages, URL schemes, skills, bundle - identifiers, or explicit compatibility and historical discussion. -- Native packages replace and conflict with the former `codex-app` and - `codex-desktop` packages. Do not ship compatibility commands, desktop files, - service aliases, or other runtime shims. Migrate wrapper-owned XDG state to - `chatgpt` and `chatgpt-updater` with the journaled migration helper; fail - closed on collisions and preserve the explicit reverse-migration command. -- Preserve this fork's intentional names when syncing from `upstream`: - the app, install roots, launchers, package names, desktop files, and XDG app - state use `chatgpt`; the updater crate, binary, service, config, state, - cache, and logs use `chatgpt-updater`. Integrate incoming behavior under - the local names instead of adopting upstream names. -- Preserve this fork's intentional layout when syncing from `upstream`. - Path decisions follow these criteria in order: the XDG Base Directory - Specification, the Filesystem Hierarchy Standard, then common conventions - used by mainstream Linux distros for modern Electron-style apps. Native - packages keep the generated app bundle under `/opt/chatgpt`, private - package support under `/usr/lib/chatgpt`, system launch and desktop - integration under `/usr/bin` and `/usr/share`, and user runtime/config/cache - and state under the appropriate XDG base directories. Do not adopt upstream - `codex-desktop-linux` or `~/.local/opt` install roots as part of a sync. -- Preserve this fork's package version contract. Native package versions come - from the official OpenAI app bundle's `CFBundleShortVersionString`, written - to `chatgpt/chatgpt-version.env` during app generation. Do not replace - that with timestamp-based package versions during upstream syncs. -- When syncing from `upstream`, use the user-global - `syncing-forks-with-upstream` skill and the repo-local policy in - `.agents/fork-sync-policy.toml`. Read - `docs/maintainers/fork-divergences.md`, - `.agents/fork-sync-policy.toml`, and - `docs/maintainers/fork-sync-policy.md` before resolving conflicts. If the - external skill is unavailable, follow the maintainer policy directly and - record the missing-skill fallback in the sync ledger. Compare upstream - user-facing docs against this fork's docs, adapting relevant facts under - local names, paths, and policy. Escalate uncertain sync decisions to the - operator when the session allows. If escalation is unavailable or the operator - requested an uninterrupted run, record a durable, discoverable follow-up and - link it from the sync ledger; do not rely on the PR body alone. -- During upstream syncs, reconcile renamed local files explicitly. - Git's merge machinery may follow renames automatically when similarity is - high enough, but agents must still check the rename map in - `docs/maintainers/fork-divergences.md`. If upstream changes an old path that - this fork renamed, port those hunks to the current local path and record the - reconciliation in the sync ledger. Do not drop changes only because the - original path is absent here. -- During upstream syncs, close reusable policy gaps before handoff. - If the sync reveals a hazard that future agents could miss, update the - narrowest durable policy surface and record the change in the sync ledger. -- Keep native-package-only launcher behavior in `packaging/linux/chatgpt-packaged-runtime.sh`; `install.sh` should stay generic and load that helper only when packaging requires it. -- Keep package builders and `scripts/lib/package-common.sh` aligned when adding, removing, or moving packaged files. -- Preserve the unprivileged updater boundary. Escalation belongs only at install time through the updater's privileged install subcommands. -- If the updater crate version changes, update `updater/Cargo.toml`, `README.md`, `AGENTS.md`, and maintainer versioning docs in the same change. - -## Source Pointers - -- Installer, ASAR patching, Electron runtime setup, generated launcher: `install.sh` -- Launcher template, webview helper, and runtime behavior: - `launcher/start.sh.template` and `launcher/webview-server.py` -- Debian package builder: `scripts/build-deb.sh` -- RPM package builder: `scripts/build-rpm.sh` -- pacman package builder: `scripts/build-pacman.sh` -- Shared package staging helpers: `scripts/lib/package-common.sh` -- Linux Computer Use backend and bundled plugin: `computer-use-linux/` and `plugins/openai-bundled/plugins/computer-use/` -- Host dependency bootstrap: `scripts/install-deps.sh` -- Linux patch registry and port integration descriptors: `scripts/patches/`, - `scripts/lib/port-integrations.js`, and `port-integrations/` -- Linux package templates, maintainer scripts, desktop entry, service unit, packaged runtime helper: `packaging/linux/` -- AppImage-only runtime behavior: `packaging/appimage/chatgpt-appimage-runtime.sh` -- Shared build pipeline: `scripts/lib/*.sh` -- Official DMG automation: `scripts/automation/upstream-dmg-watchdog/` and - `docs/upstream-dmg-watchdog.md` -- Nix package and modules: `flake.nix`, `flake.lock`, and `nix/` -- Rust updater service and CLI: `updater/` -- Updater crate version and versioning policy: `updater/Cargo.toml` and - `docs/maintainers/package-runtime-maintenance.md` (current version: `0.10.4`) -- User-facing overview and install guidance: `README.md` -- Webview server design decision and acceptance criteria: `docs/webview-server-evaluation.md` -- Fork-specific contracts and upstream sync review inventory: `docs/maintainers/fork-divergences.md` -- Upstream sync policy, local gates, and sync ledger requirements: - `docs/maintainers/fork-sync-policy.md` and `.agents/fork-sync-policy.toml` -- Security follow-up and `@codex-security` review routing: `docs/maintainers/security-backlog.md` -- Additional maintainer notes: prefer `docs/maintainers/` over expanding this file. - -## Patch And Integration Rules - -- Treat `scripts/patch-linux-window-ui.js` as a build-facing CLI. Use the - descriptor, runner, and helper APIs under `scripts/patches/` for patch work. -- Keep ASAR patches fail-soft and idempotent unless a descriptor is deliberately - marked `required-official-dmg`. -- Do not recreate deleted compatibility barrels such as - `scripts/patches/main-process.js`, `webview-assets.js`, or `shared.js`. -- Port integrations patch through `entrypoints.patchDescriptors`. Prefer - declarative `resources`, `runtimeHooks`, and `packageHooks` to ad hoc - staging, and keep resource targets inside the app directory. - -## Triggered Guidance - -- Changing launcher behavior: edit `launcher/start.sh.template`; if install-time launcher identity or orchestration is involved, edit `install.sh`; if package-only behavior is involved, edit `packaging/linux/chatgpt-packaged-runtime.sh`; then regenerate or inspect `chatgpt/start.sh`. -- Changing ASAR patches or Linux window behavior: edit the patching path from `install.sh` and `scripts/patch-linux-window-ui.js`; keep patches fail-soft when they target volatile official app bundles. -- Changing webview serving: read `docs/webview-server-evaluation.md` before changing the local server model or port behavior. -- Changing package contents: update the relevant file under `packaging/linux/`, the affected package builder, and `scripts/lib/package-common.sh` together. -- Changing updater behavior: work in `updater/`, preserve persisted-state compatibility unless intentionally versioned, and check service/install behavior around failed, cancelled, or interrupted privileged installs. -- Changing updater service lifecycle: inspect `packaging/linux/chatgpt-updater.service` and the package maintainer scripts for Debian, RPM, and pacman effects. -- Changing runtime CLI discovery or install behavior: keep the launcher best-effort; warnings may not block Electron startup unless the task explicitly changes that policy. -- Changing dependencies or supported runtime requirements: update `scripts/install-deps.sh`, `README.md`, and package metadata or maintainer docs as needed. -- Syncing from `upstream`: use the user-global - `syncing-forks-with-upstream` skill, read - `docs/maintainers/fork-divergences.md`, `.agents/fork-sync-policy.toml`, and - `docs/maintainers/fork-sync-policy.md`, then triage incoming changes against - the intentional fork contracts before pushing. If the external skill is - unavailable, follow the maintainer policy directly and record that fallback in - the sync ledger. - -## Generated And Runtime Artifacts - -- `chatgpt/` and side-by-side `*-app/` directories: generated Linux app trees and launcher output. -- `chatgpt/chatgpt-version.env`: generated package-version metadata read - from the official OpenAI app bundle. -- `dist/`: native package output. -- `ChatGPT.dmg`: cached official OpenAI ChatGPT DMG. -- `~/.config/chatgpt-updater/config.toml`: updater runtime config. -- `~/.local/state/chatgpt-updater/`: updater state and service logs. -- `~/.cache/chatgpt-updater/`: downloaded DMGs, rebuild workspaces, staged packages, and build logs. -- `~/.cache/chatgpt/launcher.log` and `~/.local/state/chatgpt/app.pid`: launcher diagnostics and app liveness state. - -Inspect generated artifacts to verify behavior, but do not make them the only source of a durable fix. - -## Validation Policy - -Choose the smallest validation set that covers the changed behavior. - -- Shell changes: run `bash -n` on edited shell scripts. -- Updater changes: run `cargo check -p chatgpt-updater` and targeted updater tests; run full updater tests for state, install, or CLI changes. -- Package changes: build the affected package format when practical and inspect package metadata plus the first package file listing. -- Launcher or installer changes: regenerate or inspect `chatgpt/start.sh` and check launcher logs when runtime behavior is involved. -- Webview changes: verify the local server still serves expected ChatGPT webview startup assets before Electron launch. - -If a preferred validation cannot run because a host tool is missing, state the missing tool and run the closest useful static or targeted check. +This repository is the retired, unsupported source record for ChatGPT for +Linux. It is a local hardening and finishing fork layered over the Linux-port +upstream, [`ilysenko/codex-desktop-linux`](https://github.com/ilysenko/codex-desktop-linux). +It is not the primary Linux port and is not affiliated with, endorsed by, +sponsored by, or supported by OpenAI. + +The validated native repackage is the settled producer. The authoritative +current boundary is [Repository Retirement](docs/retirement.md). The +[official-app parity record](docs/maintainers/research/official-app-parity-2026-08.md) +and +[rollback-evidence retention record](docs/maintainers/research/rollback-evidence-retention-boundary-2026-08.md) +preserve the accepted evidence. + +## Retirement Boundary + +Work in this repository is limited to the explicitly authorized retirement +route: + +- correct or preserve the public record; +- disposition existing issues and pull requests transparently; +- export a bounded, still-useful source improvement when its owning closeout + ticket authorizes that export; and +- complete the repository archive ticket after its gates pass. + +Do not start or resume builds, releases, dependency refreshes, upstream syncs, +DMG or hash campaigns, package or updater maintenance, support work, feature +work, compatibility work, or security remediation. Do not recreate, enable, or +dispatch retired automation. A new owner initiative must explicitly reverse +retirement before any of those activities can begin. + +Open Dependabot and code-scanning alerts are unresolved retired risk. Do not +close them as fixed, describe them as remediated, or start a maintenance cycle +to address them. + +The delayed M3 package-lifecycle check and M4 deletion of private fallback and +recovery evidence belong to `nisavid/arch-pkgs` issues +[#76](https://github.com/nisavid/arch-pkgs/issues/76) and +[#77](https://github.com/nisavid/arch-pkgs/issues/77). Do not inspect, move, +delete, or publish that private evidence from this repository. + +## Language + +- The project prose name is **ChatGPT for Linux**. The repository and checkout + name is `chatgpt-linux`; the historical runtime and package identity is + `chatgpt`. +- `Linux-port upstream` means `ilysenko/codex-desktop-linux`. Do not call this + repository “the Linux fork.” +- Preserve `Codex` for inherited OpenAI interfaces such as the Codex CLI, + protocols, packages, skills, bundle identifiers, and explicit historical + discussion. Do not use it as this application or project's name. +- Use `port integration` for the historical configurable modules under + `port-integrations/`. Do not present them as maintained Linux features. +- Use `CHATGPT_*` for variables introduced by this fork or the Linux-port + upstream. Keep inherited OpenAI `CODEX_*` interfaces unchanged. + +## Git And Pull Requests + +- `main` is protected. Create a task branch before editing. +- Use `checkpointing-and-publishing-git-work` for every Git-backed task and + commit only task-owned paths. +- The first push of a task branch must create a draft pull request in the same + workflow turn. +- Use `publishing-reviewable-prs` for every PR creation, title/body mutation, + and draft/ready transition. Use `writing-reviewable-pr-descriptions` for the + complete reviewer-facing title and body. Never use `gh pr create --fill` or + its variants. +- Use `--repo nisavid/chatgpt-linux` on every `gh pr` command in this checkout. +- Use Conventional Commits and prefer rebase merge when repository policy + permits it. +- Do not merge or archive until the active ticket's exact checks, reviews, + tracker prerequisites, and ownership gates pass. + +## Tracker And Archive Work + +- Read an issue or pull request's operator-owned checklist before mutation. + Update only checklist items owned by the operator and authorized by the + active task. +- Preserve contributor credit and distinguish “retired without fix” from + “fixed.” +- Do not open replacement maintenance tasks. Route delayed rollback cleanup to + the existing `arch-pkgs` owners. +- Repository archival is owned by the dedicated archive ticket. Archival must + preserve the Git history, fallback tag, research, issue and PR record, and + historical Actions runs. + +## Source And State Safety + +Treat `chatgpt/`, side-by-side `*-app/` output, `dist/`, `ChatGPT.dmg`, updater +paths, XDG application state, caches, logs, profiles, and recovery material as +generated or user-owned state. Retirement documentation and tracker work does +not authorize mutating any of it. + +Do not build or hand-edit generated app output. Do not mutate installed +packages, host services, package repositories, user state, private rollback +evidence, or credentials from this repository's closeout tasks unless a +separate task names the exact target and grants that authority. + +## Documentation + +- `README.md` is the user-facing retirement landing page. +- `docs/retirement.md` is the current maintainer and support boundary. +- `docs/README.md` separates the current retirement record from historical + build, package, updater, DMG, sync, and architecture documents. +- Historical instructions may remain for source interpretation, but must be + labeled historical and must not compete with the retirement route. +- In committed docs and PR text, use repository-relative paths and public URLs, + never machine-local absolute paths. + +## Validation + +Choose the smallest checks that cover the closeout change. Retirement posture +or automation changes must run: + +```bash +node --test scripts/ci/retirement-posture.test.js +bash -n tests/scripts_smoke.sh +git diff --check +``` + +Run the broader relevant Node or documentation checks when changed files share +their surface. Before finalization, review the exact immutable diff and refresh +thread-aware pull request state. diff --git a/CONTEXT.md b/CONTEXT.md index fc3674ab1..9d809a732 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -32,14 +32,20 @@ This repository's hardening, packaging, policy, and runtime-polish layer over the Linux-port upstream. _Avoid_: Linux fork, primary Linux port +**Retired finishing fork**: +The unsupported, read-only project record after the validated native repackage +became the settled producer. It preserves source and evidence but performs no +new build, release, update, sync, support, or security-remediation work. +_Avoid_: maintained fallback, supported package source, active Linux port + **Fallback baseline**: The finishing fork at its tagged, fully verified rename-completion commit, -retained with exact package evidence as a reinstallable alternative while -OpenAI's official Linux app is evaluated. +retained with exact private package evidence through downstream M3 and released +only through the target-specific M4 cleanup gate. _Avoid_: co-installed fallback, permanent parallel distribution **Evaluation transition**: -The period in which one Linux host may alternate between mutually exclusive +The completed period in which one Linux host could alternate between mutually exclusive official and finishing-fork `chatgpt` installations while the inherited `codex` CLI remains available as a continuity harness. _Avoid_: co-installation, dual ChatGPT installation @@ -93,9 +99,9 @@ _Avoid_: entire-home archive, cache backup, worktree migration **Retained fallback artifact**: The exact verified finishing-fork package, digest, source revision, payload -manifest, and verification record kept outside the package-manager cache until -the sunsetting decision. Rollback installs this artifact rather than rebuilding -or selecting a nominally equivalent version. +manifest, and verification record kept outside the package-manager cache +through downstream M3. M4 owns its final disposition; repository retirement +does not rebuild, publish, or delete it. _Avoid_: pacman-cache-only fallback, version-only rollback **Active update authority**: @@ -118,20 +124,17 @@ evaluated after switch acceptance. _Avoid_: in-place package upgrade, parity decision as installation failure **Maintenance fallback**: -The fallback baseline's interim posture: latest-DMG compatibility, security, -packaging, and essential parity repairs without discretionary feature growth. -The rename-completion package remains the designated rollback artifact until a -later repair produces its own tagged, fully verified package, digest, source -revision, payload manifest, and verification record and is explicitly promoted -as the new rollback target. “Latest-DMG” identifies the verified official DMG -used to build that maintenance candidate; it does not change the retained -artifact by itself. -_Avoid_: feature expansion, frozen archive +The historical interim posture that allowed latest-DMG, security, packaging, +and essential-parity repairs while the official Linux producer was evaluated. +The retirement decision ended this posture; it must not be used to start a new +repair or fallback build. +_Avoid_: current support policy, authorization to rebuild **Sunsetting decision**: -The later owner decision to retire or retain the finishing fork after the -official Linux app has been evaluated against the project's essential goals. -_Avoid_: automatic retirement, rename-completion decision +The completed owner decision to retire and archive the finishing fork after the +validated native repackage passed the essential-goal audit. Repository archival +does not wait for downstream M3/M4 evidence cleanup. +_Avoid_: automatic retirement, unresolved evaluation, M3/M4 archive blocker **Linux-port upstream**: `ilysenko/codex-desktop-linux`, the direct upstream whose synced baseline diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7f4f06584..0cf67d66e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,342 +1,19 @@ # Contributing to ChatGPT for Linux -Thanks for your interest in contributing to ChatGPT for Linux. This project adapts the official macOS ChatGPT DMG into a runnable Linux app, packages it for multiple Linux distributions, and maintains the local Rust `chatgpt-updater` for future rebuilds. - -> [!NOTE] -> This is an unofficial, non-affiliated community project. OpenAI owns ChatGPT, -> Codex, the official app, and its hosted services. Contributions are licensed -> only for this repository's source and packaging work; they do not change the -> ownership or terms of the downloaded OpenAI app and services. - -> [!IMPORTANT] -> Keep one pull request open at a time. The default maximum is two active pull -> requests from one contributor, reserved for exceptional cases; automation may -> close work above the effective limit. -> -> Target the latest official `ChatGPT.dmg` and current `ChatGPT.app` bundle. -> When repairing official-app drift, remove obsolete fallback patch paths and -> version-specific compatibility branches in the same pull request. - -Contributions of all sizes are welcome: bug reports, documentation improvements, packaging fixes, installer updates, tests, and new features. - -## Pull Request Best Practices - -- Keep each pull request focused: one bug fix, one feature, or one maintenance change. -- Touch the minimum set of files needed to solve the problem. -- Avoid mixed pull requests that combine unrelated fixes, refactors, formatting, docs, or cleanup. -- Think through the impact on every supported path: source installs, `.deb`, `.rpm`, pacman packages, Nix, updater rebuilds, and different desktop environments. -- Preserve existing platform behavior unless the pull request explicitly explains why it must change. -- Use `CHATGPT_*` for port-owned environment variables. Preserve inherited OpenAI `CODEX_*` CLI, plugin, app-server, and protocol interfaces. -- Keep package transitions free of compatibility commands and service aliases; use the journaled state migration for former `codex-app` XDG data. -- Keep common launch and runtime compatibility in core. Put configurable - workflow-specific, editor-specific, browser-specific, or distro-specific - behavior in a `port-integrations/` module; reviewed integrations may be - enabled by default. -- Include a short summary, the user-visible behavior change, and the validation you ran. - -## Before You Start - -Please take a moment to understand how this repository is structured before making changes. - -- `install.sh` is the top-level installer entrypoint. Build-pipeline logic lives in `scripts/lib/*.sh` (DMG handling, ASAR patching, native modules, Electron download, bundled plugins) and the runtime launcher body lives in `launcher/start.sh.template`. Edit the template for launcher behavior and a lib file for build-pipeline behavior — `install.sh` itself is just orchestration plus the prelude that bakes install-time identity into the generated launcher. -- `scripts/build-deb.sh`, `scripts/build-rpm.sh`, and `scripts/build-pacman.sh` package an already-generated `chatgpt/`. -- `scripts/install-deps.sh` bootstraps local development dependencies. -- `updater/` contains the Rust update manager. -- `scripts/patch-linux-window-ui.js` is the build-facing ASAR patch CLI. Patch - descriptors and implementations live under `scripts/patches/`; edit those - sources for Linux patch behavior. -- `chatgpt/` and `dist/` are generated artifacts and should not be treated as primary source unless you are intentionally validating generated output. - -For repository-specific implementation details, read [`AGENTS.md`](./AGENTS.md) and the relevant sections in [`README.md`](./README.md) before starting work. - -## Ways to Contribute - -You can help by: - -- reporting bugs or regressions -- proposing UX or packaging improvements -- improving Linux compatibility across distributions and desktop environments -- fixing installer, launcher, updater, or packaging issues -- adding or improving tests -- improving documentation - -## Reporting Issues and Proposing Changes - -Before opening a new issue or pull request: - -- search existing issues and pull requests to avoid duplicates -- gather as much context as possible, especially distro, desktop environment, package format, and exact reproduction steps -- include logs or command output when relevant - -Good issue reports usually include: - -- distro and version -- package format used: `.deb`, `.rpm`, `.pkg.tar.zst`, or dev build -- whether the issue happens in `install.sh`, packaged runtime, updater, or generated launcher -- exact commands used -- expected behavior -- actual behavior - -## Development Setup - -The recommended local setup is: - -```bash -git clone https://github.com/nisavid/chatgpt-linux.git chatgpt-linux -cd chatgpt-linux -bash scripts/install-deps.sh -``` - -This project requires: - -- `python3` -- `7z` or `7zz` -- `curl` -- `unzip` -- `make` -- `g++` -- Rust toolchain with `cargo` - -System Node.js 20+ with `npm` and `npx` is required for JavaScript development -and tests. Normal installer, package, Browser Use, and updater rebuild flows use -the managed runtime that the generated app bundles. - -If you are working on apt-based systems, prefer the bootstrap path in `scripts/install-deps.sh` so you get a compatible Node.js version. - -## Recommended Contribution Flow - -1. Find or open an issue. -2. Comment on the issue if you plan to work on it, especially for non-trivial changes. -3. Fork the repository and create a focused branch. -4. Read the relevant source-of-truth files before editing generated output. -5. Implement the smallest correct change that solves the problem. -6. Add or update tests. -7. Run the appropriate validation commands locally. -8. Open a pull request with a clear summary, scope, and validation notes. -9. Stay engaged after opening the PR and respond to review comments promptly. - -## Engineering Standards - -Contributions should prioritize maintainability, clarity, and safe behavior across Linux distributions. - -### Coding Standards - -- Follow the existing style and conventions of the surrounding code. -- Prefer small, focused changes over broad refactors. -- Keep shell scripts readable, defensive, and explicit. -- Keep Rust code idiomatic, strongly typed, and easy to test. -- Avoid introducing hidden coupling between installer, generated launcher, packaging, and updater behavior. -- Do not patch generated artifacts when the real source of truth is elsewhere. - -### Design Principles - -All changes should respect these principles: - -- `SOLID`: keep responsibilities separated and interfaces clear -- `Clean Code`: optimize for readability and maintainability -- `DRY`: avoid duplicated logic when a shared helper or source of truth is more appropriate -- `YAGNI`: do not add speculative features or abstractions -- `KISS`: prefer the simplest solution that correctly solves the problem - -When these principles conflict, prefer the option that keeps the repository easier to maintain and reason about. - -### Source-of-Truth Discipline - -This repository has generated outputs, and changes must respect the real ownership boundaries. - -- Prefer changing `launcher/start.sh.template` (runtime/launcher behavior) or the relevant `scripts/lib/*.sh` module (build-pipeline behavior) over editing `chatgpt/start.sh` or the top-level `install.sh` directly. -- Prefer changing packaging templates and helper scripts over editing staged package output. -- Prefer changing updater source under `updater/` over working around behavior in tests or generated files. -- If behavior differs between generated artifacts and source, fix the source and regenerate or revalidate. - -## Testing and Quality Requirements - -Every behavioral change should be validated. Do not rely on reasoning alone. - -### TDD Expectation - -Use TDD for functional changes whenever practical. - -- Write or update a failing test first for bug fixes and new behavior. -- Implement the smallest change necessary to make the test pass. -- Re-run the targeted test and then the broader relevant validation suite. - -For bug fixes, the preferred pattern is: - -1. reproduce the bug with a test -2. confirm the test fails for the right reason -3. implement the fix -4. confirm the test passes -5. run the surrounding suite to catch regressions - -### Required Quality Bar - -Contributors are expected to: - -- test any code change -- update tests when behavior changes -- avoid merging unverified fixes -- keep CI green -- leave the codebase at least as clean as they found it - -### Recommended Validation Commands - -Run the subset that matches your change. For installer, packaging, or updater work, these are the baseline commands: - -```bash -bash -n install.sh -bash -n scripts/lib/*.sh -bash -n launcher/start.sh.template -bash -n scripts/install-deps.sh -bash -n scripts/build-deb.sh -bash -n scripts/build-rpm.sh -bash -n scripts/build-pacman.sh -cargo check -p chatgpt-updater -cargo test -p chatgpt-updater -bash tests/scripts_smoke.sh -``` - -If your change affects generated app output, the installer, ASAR patcher, -package builders, package payload, updater rebuild flow, or bundled runtime -helpers, also run `./install.sh` or `make build-app` before pushing. - -If your change affects packaging, also run the relevant package builds: - -```bash -./scripts/build-deb.sh -./scripts/build-rpm.sh -./scripts/build-pacman.sh -``` - -If your change affects launcher behavior, inspect the generated launcher: - -```bash -sed -n '1,160p' chatgpt/start.sh -``` - -If your change affects updater behavior, inspect runtime state where appropriate: - -```bash -systemctl --user status chatgpt-updater.service -chatgpt-updater status --json -sed -n '1,160p' ~/.local/state/chatgpt-updater/state.json -sed -n '1,160p' ~/.local/state/chatgpt-updater/service.log -``` - -When a command is not applicable or not available in your environment, mention that clearly in the pull request. - -## Working With Agents - -If you use AI coding agents or sub-agents while contributing, apply structured, reviewable workflows. - -### SDD Expectation - -Use SDD, meaning subagent-driven development, only in a disciplined way. - -- Break work into small, well-scoped tasks. -- Delegate only bounded tasks with clear ownership. -- Do not allow multiple agents to edit the same files without coordination. -- Review agent output before considering the work complete. -- Re-run tests yourself after integrating agent-generated changes. -- Treat agent output as draft engineering work, not as verified truth. - -Good uses of agents include: - -- isolated documentation updates -- targeted test additions -- small, disjoint code changes -- codebase exploration for specific questions - -Bad uses of agents include: - -- broad unsupervised refactors -- overlapping edits to the same subsystem -- skipping local validation because the agent claims success - -## Versioning Rules - -This repository has explicit versioning expectations for the updater crate. - -- bump `patch` for fixes, docs, and maintenance-only updates -- bump `minor` for backward-compatible feature additions -- bump `major` for incompatible CLI, persisted-state, or install-flow changes - -If you change the updater crate version: - -- update the relevant documentation such as `README.md`, `AGENTS.md`, and - `docs/maintainers/package-runtime-maintenance.md` -- ensure the version bump matches the real user-facing impact - -If you are not sure which version bump is appropriate, ask in the issue or pull request before finalizing the change. - -## Pull Request Expectations - -A good pull request should be easy to review and easy to validate. - -### Keep PRs Focused - -- Submit one logical change per PR when possible. -- Avoid mixing unrelated refactors with bug fixes or feature work. -- Call out any follow-up work that you intentionally left out of scope. - -### PR Description Checklist - -Include: - -- what changed -- why it changed -- the source-of-truth files edited -- how it was tested -- any distro, package, or environment limitations -- any known risks or follow-up items - -### Review Comments - -If you open a PR, stay attentive to review comments. - -- respond to reviewer feedback clearly and respectfully -- push follow-up commits promptly when changes are requested -- explain tradeoffs when you disagree -- do not ignore unresolved comments -- re-run relevant validation after applying review feedback - -If a reviewer raises uncertainty about versioning, compatibility, packaging, or updater behavior, resolve that uncertainty before considering the PR ready to merge. - -## Commit Quality - -Make commits intentional and readable. Conventional Commits must be used for -all commits, using the format described by the -[Conventional Commits specification](https://www.conventionalcommits.org/). -Use examples in this repository as the local style guide; CI and maintainer -review may reject commits that do not follow the format. - -- use Conventional Commits for all commits -- keep commits focused and reviewable -- avoid mixing formatting-only noise with functional changes unless necessary - -## Documentation Expectations - -Update documentation when behavior, developer workflow, packaging, or versioning expectations change. - -Examples: - -- installer behavior changes -- packaging dependency changes -- updater behavior changes -- new required validation steps -- versioning policy updates - -## What to Avoid - -Please avoid: - -- editing generated output instead of the real source of truth -- introducing speculative abstractions -- skipping tests for behavioral changes -- silently changing user-facing behavior without documentation -- bundling unrelated cleanups into the same PR -- leaving reviewer comments unresolved - -## Thank You - -Every improvement helps make ChatGPT for Linux more reliable across distributions, desktop environments, and packaging formats. Thanks for taking the time to contribute thoughtfully. +ChatGPT for Linux is retired and unsupported. This repository is not accepting +contributions, bug reports, feature requests, package requests, compatibility +work, or security fixes. Do not open an issue or pull request to resume builds, +releases, upstream syncs, DMG refreshes, installer or updater work, or routine +maintenance. + +The remaining repository activity is limited to owner-directed retirement +closeout. [`docs/retirement.md`](docs/retirement.md) records that boundary and +routes reports to currently maintained owners. Existing issues and pull +requests remain visible as historical evidence; unresolved work is not an +invitation to continue it here. + +This was an unofficial community project layered over the Linux-port upstream, +[`ilysenko/codex-desktop-linux`](https://github.com/ilysenko/codex-desktop-linux). +It is not affiliated with, endorsed by, sponsored by, or supported by OpenAI. +OpenAI owns ChatGPT, Codex, the official app, and the OpenAI-hosted services +referenced by the historical source. diff --git a/DESIGN.md b/DESIGN.md index 7c0afb280..e612ea59c 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -41,6 +41,11 @@ spacing: # Design System: ChatGPT for Linux +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [Repository Retirement](docs/retirement.md). + ## Overview **Creative North Star: "ChatGPT-Native Finishing Layer"** diff --git a/PRODUCT.md b/PRODUCT.md index e6c5d4f49..c8ccda4b6 100644 --- a/PRODUCT.md +++ b/PRODUCT.md @@ -1,107 +1,30 @@ -# Product +# Historical Product Record -## Register - -product - -## Users - -ChatGPT for Linux serves Linux ChatGPT app users who want the official ChatGPT -desktop app experience, including its Codex coding workflows on a local workstation, especially package-managed -install users who prefer a native package over a one-off generated tree. - -It also serves distro/package maintainers and repo maintainers validating -package, updater, and runtime behavior. These users need native package -payloads, updater behavior, local runtime helpers, support routing, and -security evidence to stay auditable. They are often debugging a build, checking -a package, validating an updater path, or deciding whether a visual change -belongs in OpenAI's ChatGPT app, the Linux-port upstream, or this fork. - -## Product Purpose - -ChatGPT for Linux preserves the official ChatGPT app experience while this fork -adds the local finishing layer needed for Linux package workflows. The -repository keeps the `chatgpt` identity, distro-shaped install layout, -updater policy, hardening posture, port integration defaults, and maintainer -workflow coherent on top of the Linux-port upstream's conversion work. - -Success means a user can build, install, launch, update, and troubleshoot a -local ChatGPT desktop app without the fork visually or verbally pretending to own -behavior that still comes from the official OpenAI app bundle and -OpenAI-hosted services. It also means future UI and visual-design work can cite -stable product language before changing layout, copy, screenshots, empty -states, settings surfaces, connected-state presentation, or visual acceptance -criteria. +> [!IMPORTANT] +> This repository is retired and unsupported. Do not use this to start +> or continue product, design, implementation, packaging, or release work. See +> [Repository Retirement](docs/retirement.md). -## Product Surfaces - -The official app experience includes the conversation shell, left navigation -rail, pinned and project chat lists, right-side panels, side chat, file preview, -Plugins and Skills directories, Automations, command/search palettes, overflow -menus, and Settings. - -Settings are a core product surface, not an afterthought. Future work should -preserve the official app's compact, auditable settings vocabulary across -work-mode choices, appearance controls, approval and sandbox policy, custom -instructions, keyboard shortcuts, MCP servers, hooks, connections, Git, -environments, worktrees, Browser, and Computer Use surfaces. Fork-owned package, -updater, startup, support-routing, and port integration controls should fit -that settings vocabulary when they surface in the app. - -## Brand Personality - -ChatGPT-native, coding-focused, restrained, precise, trustworthy. - -The product should feel like the official ChatGPT desktop app first. Local desktop affordances, package -state, updater details, and port integration controls should fit into the -official app's practical product vocabulary instead of becoming a separate -Linux showcase identity. - -## Anti-references - -- A generic Linux showcase that centers distro identity, terminal aesthetics, - or community-port novelty ahead of the ChatGPT product. -- Fake or painted-over screenshots, invented controls, simulated product - state, fabricated metrics, or UI captures that alter product meaning. -- Mac-only copy in Linux captures or fork-authored UI, including copy that says - a Linux desktop is a Mac. -- Claims or visuals that imply OpenAI supports or publishes this fork, that this - repository is OpenAI's official Linux distribution, that it redistributes - OpenAI software, or that the fork bypasses OpenAI-hosted account, rollout, - MFA, remote-control, Browser Use, Computer Use, or service policy gates. -- Durable docs or PR text that describe this repository with a generic - Linux-fork label. Describe it as a local hardening and finishing fork layered - over the Linux-port upstream's work. -- Visual design that treats port integrations as Linux-only capabilities rather - than configurable build-time modules that adapt official app behavior or local - runtime helpers to this Linux port. +## Register -## Design Principles +historical product record -1. ChatGPT first. Preserve the official ChatGPT app's product feel, interaction - density, and practical tone unless this fork owns the surface being changed. -2. Linux context only where useful. Expose package, updater, desktop, and port - integration details when they help users make correct local decisions. -3. Evidence before polish. Use real generated app output, real source patches, - real screenshots, and reproducible visual-capture pipelines. Record evidence - gaps instead of inventing design language. -4. Do not fabricate service or host state. Connected-looking UI must not imply - enrollment, MFA completion, host liveness, thread visibility, authorization, - remote environment state, or OpenAI account availability that was not - actually verified. -5. Keep maintainer surfaces scannable and auditable. Package, updater, - security, and support-routing information should be quiet, direct, and easy - to compare during repeated maintenance work. +This non-executable historical record summarizes the product intent at the +last maintained state. -## Accessibility & Inclusion +The project provided Linux users with a package-managed desktop experience +derived from the official ChatGPT app. Its finishing layer preserved the +`chatgpt` identity, native package layout, local updater, runtime hardening, +and reviewed port integrations without claiming OpenAI support or ownership of +hosted service behavior. -Fork-authored UI overlays, docs screenshots, and visual acceptance criteria -should target WCAG 2.2 AA. At minimum, future UI and visual work should preserve -keyboard access, visible focus, sufficient text and state contrast, reduced -motion alternatives, and color-independent status communication. +The product intent centered ChatGPT rather than distro identity or +community-port novelty. It called for fork-authored surfaces to be restrained, +auditable, privacy-conscious, and visually compatible with the official app. +Those surfaces were not to fabricate account state, enrollment, authorization, +remote liveness, metrics, or service availability. -Visual evidence must be privacy-safe. Committed screenshots and README showcase -assets should use non-sensitive, reproducible staged content and should avoid -private accounts, private paths, private repositories, credentials, hostnames, -tokens, unrelated browser tabs, and visual states that imply unsupported -OpenAI-hosted service behavior. +The signed official Linux package superseded this product route. Git history +retains the detailed audience, interface, accessibility, and design principles +as evidence; this repository no longer accepts product evolution or visual +change work. diff --git a/README.md b/README.md index 94e0a5575..3c95914d1 100644 --- a/README.md +++ b/README.md @@ -1,666 +1,75 @@
ChatGPT for Linux project logo

ChatGPT for Linux

-

A hardened, package-ready ChatGPT desktop build for Linux.

-

- Packages: deb, rpm, pacman - Updater: chatgpt-updater - Focus: hardening and polish -

+

Retired source record for an unofficial Linux finishing fork.

-This build currently converts the official OpenAI ChatGPT app from its macOS -DMG. It layers package identity, updater policy, hardening, and runtime polish -over the Linux conversion work from -[`ilysenko/codex-desktop-linux`](https://github.com/ilysenko/codex-desktop-linux), -aimed at users who want a polished local app and maintainers who want auditable -native packages. - -> [!NOTE] -> OpenAI has released its official ChatGPT app for Linux in preview. We are -> evaluating whether it meets this project's essential feature-parity and -> operating needs. If the official release is acceptable, ChatGPT for Linux -> will be sunset. Until that decision, this project remains a maintained -> fallback. - -On CachyOS, the accepted evaluation path is the signed -`chatgpt-desktop-bin` native repackage after it passes the project's independent -validation gate against OpenAI's package. That package and this project's native -packages both use the `chatgpt` package and command name, so they are mutually -exclusive on one host. For that CachyOS/pacman path, the accepted -[official-app evaluation switch procedure](docs/maintainers/package-runtime-maintenance.md#official-app-evaluation-switch) -preserves shared state and one active update authority while maintainers -alternate between them. OpenAI's official Linux package is not this fork's -current build source. - > [!IMPORTANT] -> **ChatGPT for Linux is an unofficial community project.** It is not affiliated -> with, endorsed by, sponsored by, or supported by OpenAI. OpenAI owns ChatGPT, -> Codex, the official app, and the OpenAI-hosted services this build uses. This repository -> does not redistribute the official app bundle; it automates a local conversion -> from the official OpenAI ChatGPT DMG. The project logo is independent community -> artwork derived from Tux; it is not an OpenAI mark. Tux credit: Larry Ewing and -> The GIMP, Garrett LeSage, and IFo Hancroft. The logo's provenance, construction, -> and bounded rights assessment are documented in the -> [project-logo rights record](docs/maintainers/project-logo-rights-research.md). -> The repository license covers this fork's source code and packaging work, not -> the downloaded OpenAI app or services. Your use of OpenAI software and services -> remains subject to OpenAI's terms. - -## Start Here - -- **Normal package-managed app:** use [Quick Start](#quick-start). -- **NixOS:** use [NixOS](#nixos). -- **Checkout, custom DMG, or side-by-side test app:** use - [Manual and Custom Builds](#manual-and-custom-builds). -- **AppImage or package details:** use - [Native Package Details](#native-package-details). -- **Where to report issues:** use - [Support and Issue Routing](docs/usage/support-routing.md). -- **Computer Use, updater, release, or maintainer work:** use - [Linux Computer Use](#linux-computer-use) and [Learn More](#learn-more). -- **Port integrations and architecture:** use the - [Documentation Index](docs/README.md) to choose the catalog, configuration, - authoring, or design document for the task. - -## Quick Start - -This is the normal fast path for a package-managed install. It removes old -generated output, rebuilds the Linux app from the official OpenAI ChatGPT DMG, -builds the native package for your host, then installs that package with your -distro's package manager. - -For the guided one-command path, clone the repository and run -`make bootstrap-native`. It installs host dependencies, builds and packages -the app, and installs the resulting native package. The expanded flow below is -useful when you want to inspect the package before installing it. - -```bash -git clone https://github.com/nisavid/chatgpt-linux.git chatgpt-linux -cd chatgpt-linux -bash scripts/install-deps.sh -make clean build-app package -``` - -Install the package that `make package` wrote to `dist/`: - -```bash -# Debian / Ubuntu -sudo apt install ./dist/chatgpt_*.deb - -# Fedora 41+ -sudo dnf5 install ./dist/chatgpt-*.rpm - -# Fedora with dnf -sudo dnf install ./dist/chatgpt-*.rpm - -# openSUSE -sudo zypper --non-interactive --allow-unsigned-rpm install -y ./dist/chatgpt-*.rpm - -# Arch Linux -sudo pacman -U ./dist/chatgpt-*.pkg.tar.zst -``` - -Then launch: - -```bash -chatgpt -``` - -`scripts/install-deps.sh` supports Debian/Ubuntu-family, Fedora, openSUSE, and -Arch-family hosts. The generated package bundles a managed Linux Node.js -runtime for normal app use, Browser Use, Codex CLI install/update, and updater -rebuilds. - -On hardened systems where `/tmp` is mounted `noexec`, set `TMPDIR` and -`XDG_CACHE_HOME` to user-owned executable locations before installing or -building. See [Troubleshooting](docs/usage/troubleshooting.md) for a compact -workaround. - -For an interactive preflight summary before building, run: - -```bash -make setup-native -``` - -The guided setup helper detects the host package manager, desktop session, -package format, updater hints, Computer Use readiness signals, and optional -port integration config. It can write the git-ignored -`port-integrations/integrations.json` file for the next build, but it does not run the -build, package, or install flow unless you explicitly opt in through -`CHATGPT_BOOTSTRAP_INSTALL_DEPS=1` or `CHATGPT_BOOTSTRAP_INSTALL_NATIVE=1`. - -## Upgrading From Codex App - -The `chatgpt` packages replace the former `codex-app` and -`codex-desktop` package identities. They do not install compatibility commands, -launchers, desktop files, or service aliases. Use `chatgpt` and -`chatgpt-updater` after upgrading. - -Before ChatGPT creates any new runtime state, the launcher and updater move this -fork's existing XDG directories from `codex-app` to `chatgpt` and from -`codex-app-updater` to `chatgpt-updater`. The migration also moves the -wrapper-owned CLI quarantine directory, discards volatile pid, socket, lock, and -temporary files, rewrites known wrapper-owned paths and setting keys, and records -progress in `${XDG_STATE_HOME:-$HOME/.local/state}/.chatgpt-state-migration.json`. -Interrupted work resumes on the next launch. - -Migration is atomic and refuses symlinks, unexpected file types, cross-filesystem -moves, and collisions. If both an old and a new directory exist, no directories -are merged or replaced. Follow the exact `Recovery command:` printed by the -launcher; it moves the new directory aside and reruns `chatgpt`. To roll a -completed migration back to the former XDG names, close the app and run: - -```bash -chatgpt migrate-state --reverse -``` - -Reverse migration uses the same journal, collision checks, and fail-closed path -validation. It restores data names only; it does not reinstall the former package -or add compatibility shims. - -## Uninstall - -Close ChatGPT, then remove the native package with your distro's package -manager: - -```bash -# Debian / Ubuntu -sudo apt remove chatgpt - -# Fedora -sudo dnf remove chatgpt - -# openSUSE -sudo zypper remove chatgpt - -# Arch Linux -sudo pacman -R chatgpt -``` - -Package removal stops and disables `chatgpt-updater.service`. If a service -from an older or manual install remains, remove its user-level enablement with -`systemctl --user disable --now chatgpt-updater.service`. AppImage and -checkout builds are not system-installed; remove the artifact or generated tree -you created. User configuration and state are preserved for reinstall. - -## Highlights - -- **Distro-shaped native packages.** Builds `.deb`, `.rpm`, and pacman packages - under the `chatgpt` identity, with package-managed install roots and XDG - user state. AppImage self-builds are available for manual-update systems. -- **Updater with a narrow privilege boundary.** `chatgpt-updater` checks DMGs, - rebuilds packages, tracks state, and uses `pkexec` only for final package - installation. -- **Managed runtime and CLI preflight.** Native packages bundle the Linux - Node.js runtime used by Browser Use, Codex CLI install/update, and updater - rebuilds. -- **Release and supply-chain evidence.** The release gate verifies reviewed DMG - hashes, scans generated Electron output, validates package metadata, writes - checksums, and supports detached signatures. -- **Computer Use packaging compatibility.** The Linux-port upstream's Linux - Computer Use backend is staged under this fork's package identity while the - official persistent control, account rollout, and host accessibility gates - stay separate. - -## Current State - -- **Working:** the standard ChatGPT app UI, native packages, AppImage self-builds, - local updater, managed runtime, Codex CLI preflight, Chrome native host, - browser resources, and port integration registry. -- **Desktop-dependent:** tray behavior, warm start, multi-instance launches, - and Linux keybind handling can vary by desktop environment. -- **Host-gated:** Linux Computer Use is packaged, but real readiness depends on - local AT-SPI, screenshot portal or compositor support, `ydotool`, and input - permissions. -- **Curated port integrations:** the manifest-declared defaults cover app - workflow, project, update, remote-control, speech, theme, and status surfaces. - `make setup-native` shows the current set. Integration-specific settings, - account rollouts, MFA, connected-client, audio, and host-network requirements - still apply. -- **NixOS:** the flake exposes the default app, remote-mobile compatibility - alias, and installer output with pinned DMG metadata. Computer Use support is - part of the default app and remains subject to its official controls. -- **OpenAI-gated:** installing this fork cannot bypass server-side feature flags - or account policy. - -## About This Fork - -This fork is a downstream maintenance fork of +> **ChatGPT for Linux is retired and unsupported.** This repository no longer +> produces maintained builds, releases, updates, security fixes, or user +> support. Do not install or update ChatGPT from this repository. Its remaining +> closeout work is limited to preserving the public record and archiving the +> repository; the retirement posture is read-only even before GitHub's archive +> switch is applied. + +## Current Linux Route + +Use OpenAI's official ChatGPT application for Linux or a distribution package +whose provenance you independently accept. + +On CachyOS, this project's accepted replacement is the repository-signed +`chatgpt-desktop-bin` native repackage. Its recipe and payload were compared +with OpenAI's signed Linux package, and its essential behavior was accepted on +the transition host. It now follows ordinary unpinned pacman upgrades. This is +operational evidence for that CachyOS package, not a claim that OpenAI supports +Arch Linux or CachyOS. + +The complete decision record is in the +[official-app parity audit](docs/maintainers/research/official-app-parity-2026-08.md). +The retained fallback and recovery evidence follow the separate +[rollback-retention boundary](docs/maintainers/research/rollback-evidence-retention-boundary-2026-08.md). + +## What This Repository Preserves + +This repository is a historical source and review record for a DMG-based Linux +adaptation. It converted the official OpenAI ChatGPT macOS app locally and +layered the `chatgpt` identity, distro-shaped packaging, updater policy, +hardening, and runtime polish over the Linux conversion work from [`ilysenko/codex-desktop-linux`](https://github.com/ilysenko/codex-desktop-linux). -This fork's synced baseline carries the Linux-port upstream's core DMG-to-Linux -conversion and runtime enablement. Current Linux-port upstream development now -starts from OpenAI's official Linux package; this fork has not adopted that -source transition. It keeps the local `chatgpt` package identity, install -layout, updater policy, hardening posture, and maintenance workflow coherent on -top of the synced baseline. - -For the full inventory of fork-specific contracts, see -[`docs/maintainers/fork-divergences.md`](docs/maintainers/fork-divergences.md). - -## Manual and Custom Builds - -Use these paths when you do not want the normal package-managed install. - -Build and run directly from the checkout: - -```bash -make build-app -make run-app -``` - -`make build-app` downloads or reuses `ChatGPT.dmg`, extracts the app, patches the -macOS bundle for Linux, rebuilds native modules, downloads a Linux Electron -runtime, and writes `chatgpt/start.sh`. - -App generation is transactional. The candidate must pass the shared -[official DMG acceptance profile](docs/upstream-dmg-acceptance.md) before it -replaces the working `chatgpt/`. Acceptance checks enabled port integrations; -rejected or inconclusive candidates preserve the current app. - -On first launch, the app can install the Codex CLI if it is missing. To install -the CLI yourself with an existing `npm` command: - -```bash -npm i -g --include=optional @openai/codex -``` - -If global npm installs require elevated privileges on your system, use a -rootless prefix instead: - -```bash -npm i -g --prefix ~/.local --include=optional @openai/codex -``` - -The Linux optional dependency supplies the platform binary. The launcher uses -`CODEX_CLI_PATH` first, then its normal lookup order. It pins the resolved -executable while preserving `codex` as the invocation name for multicall -installations, and logs the selected source, pinned target, and best-effort -version for GUI `PATH` troubleshooting. - -Build from a DMG you already downloaded: - -```bash -make build-app DMG=/path/to/ChatGPT.dmg -``` - -If Electron runtime or header downloads are slow or blocked, use -`ELECTRON_MIRROR` or `ELECTRON_HEADERS_URL`; the -[Build and Run Guide](docs/usage/build-and-run.md) has the exact knobs. - -For a side-by-side test app with a distinct app id and webview port: - -```bash -make build-dev-app -make run-dev-app -``` - -Normal launches reuse a running app through the warm-start handoff. To start an -additional isolated instance instead, pass `--new-instance` or set -`CHATGPT_MULTI_LAUNCH=1`; the launcher chooses the first free webview port in a -bounded range and uses per-port pid, socket, log, and Electron user-data paths. - -```bash -./chatgpt/start.sh --new-instance -CHATGPT_MULTI_LAUNCH=1 CHATGPT_MULTI_LAUNCH_PORT_RANGE=5175-5199 ./chatgpt/start.sh -``` - -## Port Integrations - -Port integrations are build-time integration modules that adapt official ChatGPT app -behavior and local runtime helpers to this Linux port. The source path is -`port-integrations/`, but the modules are not features of Linux itself, -and their user-facing concepts are not necessarily Linux-only ChatGPT features. - -This fork enables the reviewed integration set declared by each manifest. Run -`make setup-native` to review the current defaults. The default set includes -workflow and project helpers, wrapper update UI, remote-control compatibility, -speech and dictation, theme and status helpers, API-key model metadata, shared -app-server and SSH routing, Pet Overlay, and UI Tweaks. Resource-heavy, -privilege-sensitive, or still-deferred integrations remain disabled. - -Default enablement never replaces a feature's own runtime gates. Agent Workspaces -preserves its approval and permission controls; AppShots keeps global hotkeys -inactive until configured; wrapper update checks stay off until enabled in -Settings; and Open Target Discovery validates desktop targets. UI Tweaks enables -Suggested Prompts by default; its official ChatGPT/Codex Dock-icon selector is -opt-in so the project logo remains the default app identity. When enabled, -Dock-icon synchronization creates, updates, and removes only marker-owned -ChatGPT desktop and icon files; it leaves unmanaged launchers and favorites -untouched. Suggested Prompts requires -the official app's eligibility, the user's setting, and supported local -Linux patch contracts at the same time. Main-process hardening for direct -workspace bridge calls is tracked in -[`#99`](https://github.com/nisavid/chatgpt-linux/issues/99). - -To disable default integrations, enable still-optional integrations, or set -integration-specific options, copy -`port-integrations/integrations.example.json` to the git-ignored -`port-integrations/integrations.json`, edit the `enabled` and `disabled` lists, then -rebuild. Packaged installs can use -`${XDG_CONFIG_HOME:-$HOME/.config}/chatgpt/port-integrations.json` for the same -override shape; checkout builds ignore that persistent user file and use -`port-integrations/integrations.json` or `CHATGPT_PORT_INTEGRATIONS_CONFIG` instead. -Updater rebuilds prefer the saved user override, then the resolved integration -snapshot shipped in the native package, then the legacy builder config. They do -not silently replace an available selection. If none of those three inputs -exists, the fetched wrapper's manifest defaults provide the initial selection. -See [`port-integrations/README.md`](port-integrations/README.md) for the integration -contract. - -Port integrations expose official app surfaces and local runtime helpers through -Linux-specific implementation code. Treat them as UI/runtime integrations, not -as account-policy bypasses: OpenAI rollouts, MFA state, connected-client state, -audio availability, remote-control enrollment, and host network exposure still -come from OpenAI-hosted services and your local environment. - -## Native Package Details - -Native package builders repackage the generated app tree. The quick path uses -`make clean build-app package` so the app tree, cached DMG, and old package -outputs all start fresh. - -If `chatgpt/` already exists and you only need to rebuild the package, use: - -```bash -make package -``` - -Choose a format directly when needed: - -```bash -make deb -make rpm -make pacman -``` - -`make build-app` publishes a sibling, content-addressed generation receipt -under `.chatgpt-generation-receipts/`. The receipt binds the exact mutation -broker, generated app manifest, and `.chatgpt-linux/build-info.json`. Keep the -generated app and that sibling receipt root together; native package builders -reject a missing or mismatched receipt before staging app bytes. - -The repository-approved offline `@parcel/watcher` bundle supports Linux glibc -on x86_64, arm64/aarch64, and ARMv7 hard-float hosts. App generation rejects -other platform, architecture, or libc combinations before invoking npm. - -Convenience targets are available when you want Make to run more of the native -install lifecycle: - -```bash -make bootstrap-native -make install-native -``` - -`make bootstrap-native` installs dependencies first, then runs the fresh app -build, package build, and install flow. `make install-native` assumes -dependencies are already present. - -To build a package without installing `chatgpt-updater`, its user service, or -its polkit/update-builder support files, disable the updater at package build -time: - -```bash -PACKAGE_WITH_UPDATER=0 make package -``` - -No-updater packages also remove stale `chatgpt-updater.service` enablement -when installed over a default package. They are local/manual-update artifacts; -the public release gate requires the reviewed updater and its support bundle. - -Package outputs land in `dist/`: - -| Target | Output | -| --- | --- | -| Debian | `dist/chatgpt__.deb` | -| RPM / Fedora / openSUSE | `dist/chatgpt--1..rpm` | -| Arch Linux | `dist/chatgpt--1-.pkg.tar.zst` | -| AppImage | `dist/chatgpt--.AppImage` | - -Architecture names follow the package format: Debian uses `amd64`, `arm64`, or -`armhf`; RPM uses `x86_64`, `aarch64`, or `armv7hl`; pacman uses `x86_64` or -`aarch64`. - -The package version comes from the official OpenAI app bundle's -`CFBundleShortVersionString`. For example, `26.422.30944 (2080)` becomes -`26.422.30944`. - -Native packages are named `chatgpt`. They declare replacement, conflict, and -provider metadata for the former `codex-app` and `codex-desktop` package names -where the package format supports it. They do not ship executable or service -compatibility shims. -The installed launcher is `/usr/bin/chatgpt`, and the app lives under -`/opt/chatgpt`. - -Native packages bundle the managed Node.js runtime used by the launcher, Browser -Use, Codex CLI install/update flow, and local auto-update rebuilds. They do not -hard-depend on distro `nodejs` or `npm`. - -`make install` is a convenience wrapper around the package-manager install -commands shown in [Quick Start](#quick-start). It installs the newest matching -package in `dist/`. - -For atomic desktops or systems where installing a native package is awkward, -build a local AppImage after `chatgpt/` exists: - -```bash -make appimage -./dist/chatgpt-*.AppImage -``` - -The AppImage flow omits `chatgpt-updater`, the systemd user service, polkit -policy, and the native-package update-builder bundle. Rebuild it manually when -you want a newer official OpenAI app bundle. - -To embed an installed Codex CLI and its matching Linux platform package, set -`CHATGPT_CLI_BUNDLE_SOURCE` to its `node_modules/@openai/codex` directory when -running `make appimage`. An explicit runtime `CODEX_CLI_PATH` still takes -precedence. - -Before publishing packages, build the candidate package from the Nix -`chatgpt-release-app` and `release-helpers` outputs, then run the release gate -against that app and the pinned `chatgpt-dmg` output: - -```bash -APP_DIR=/opt/chatgpt \ -DMG= \ -PACKAGE_WITH_UPDATER=1 \ -REQUIRE_RELEASE_SIGNATURE=1 \ -CHATGPT_RELEASE_GPG_KEY= \ -CHATGPT_RELEASE_GPG_FINGERPRINT= \ -make release-gate -``` - -Public mode requires a root-managed multi-user Nix daemon with sandboxing -enabled. The gate snapshots the clean source and DMG, independently builds the -portable `chatgpt-release-app` and static `release-helpers` outputs, and requires -the submitted app to match the `chatgpt-release-app` reference exactly. It then -uses that reference, not the submitted tree, as package authority. Payload and -install controls must match; RPM bytes must also match the deterministic -reference package. Public packages require `PACKAGE_WITH_UPDATER=1`. Public mode -writes signed `SHA256SUMS` and -`RELEASE-PROVENANCE.json` attestations. For a local unsigned rehearsal, set -`CHATGPT_RELEASE_REHEARSAL=1`; a default invocation is a public release and -fails without signing controls. Consumers must verify the signing-key -fingerprint against the approved value supplied to the gate through an -independently trusted project channel rather than trusting only the -co-published key. See the -[Build and Run Guide](docs/usage/build-and-run.md) and -[Package and Runtime Maintenance](docs/maintainers/package-runtime-maintenance.md) -for release details. - -## NixOS - -The flake handles dependencies and Electron patching under the local -`chatgpt` identity: - -```bash -nix run github:nisavid/chatgpt-linux -``` - -This builds the flake's default ChatGPT package in the Nix store and launches -it. Use the `#installer` app below when you specifically want a generated -`chatgpt/` directory in the current checkout. For a development shell: - -```bash -nix develop github:nisavid/chatgpt-linux -``` - -The remote-mobile output is retained as a compatibility alias for the -manifest-default-enabled mobile integration. The installer output generates -`chatgpt/` in the current checkout using the ordinary port integration -selection: - -```bash -nix run github:nisavid/chatgpt-linux#chatgpt-remote-mobile-control -nix run github:nisavid/chatgpt-linux#installer -``` - -For a declarative NixOS or Home Manager install with the mobile remote-control -app-server managed by systemd, import the flake module: - -```nix -{ - imports = [ - inputs.chatgpt-linux.homeManagerModules.default - ]; - - programs.chatgptLinux = { - enable = true; - remoteMobileControl.enable = true; - remoteControl.enable = true; - }; -} -``` - -`nixosModules.default` is also available for system-level configurations that -prefer a global user unit. - -If `nix run` reports a DMG metadata mismatch, OpenAI likely republished the -ChatGPT DMG after the pinned metadata changed. A scheduled GitHub Actions job -refreshes that metadata and verifies the Nix package outputs on `main`. Retry -after the bot has had time to run; if it still fails, open an issue. - -## Linux Computer Use - -Linux Computer Use support is packaged from the Linux-port upstream's Rust MCP -backend. The backend can inspect apps through AT-SPI, capture screenshots -through XDG Desktop Portal or compositor paths, and synthesize input through a -uinput absolute pointer, XDG Desktop Portal RemoteDesktop sessions, or -`ydotool` when the host is configured for them. - -Runtime readiness depends on the host. Input synthesis usually requires -`ydotool`/`ydotoold`, `/dev/uinput` access, and a socket usable by your desktop -user. Non-GNOME desktops usually also need the matching XDG Desktop Portal -backend, such as the KDE or wlroots portal. - -Keyboard input follows the desktop's active keyboard layout and remapping. When -troubleshooting literal keys or shortcuts on a non-QWERTY layout, retry once with -a standard US/QWERTY layout before debugging lower-level input services. Some -apps also expose only sparse AT-SPI trees even when the backend is ready; -screenshot and pointer paths can still work for those apps. - -The plugin manifest and Linux support patches are applied by default so the -backend can register when the official app is eligible. OpenAI account and -rollout policy, ChatGPT's persistent Computer Use and allowed-app controls, and -Codex tool approval, sandboxing, and auto-approval policy remain authoritative. -This fork adds no duplicate consent prompt or setting. Disable or revoke -Computer Use through those existing controls; future ChatGPT-originated actions -must then be rejected. OS portal prompts may still appear when the desktop owns -that permission. - -Linux support and host readiness determine whether an authorized action can -succeed. They are not separate permissions and do not bypass OpenAI policy. - -After building the app, check local readiness with: - -```bash -./chatgpt/resources/plugins/openai-bundled/plugins/computer-use/bin/chatgpt-computer-use-linux doctor -``` - -## Local Updater - -Native packages install `chatgpt-updater`, a `systemd --user` service that -checks for newer official OpenAI ChatGPT DMGs, rebuilds the matching Linux package -locally, and uses `pkexec` only for the final package install step. - -Current updater crate version: `0.10.4`. - -Useful service commands after installing a native package: - -```bash -make service-enable -make service-status -chatgpt-updater status --json -``` - -The packaged launcher also starts the user service on a best-effort basis when -you open the app. - -If a rebuilt update installs but the previous retained package was better, -close ChatGPT and run: - -```bash -chatgpt-updater rollback -``` - -Rollback uses the last retained known-good package and refuses to run when no -rollback package is available. - -## Troubleshooting - -Start with the launcher log: - -```bash -sed -n '1,160p' ~/.cache/chatgpt/launcher.log -``` - -Common next steps: - -- blank window or splash hang: check whether something else is serving port - `5175`; -- Codex CLI warning: install `@openai/codex` with optional packages globally - or under `~/.local`; -- hardened `/tmp` with `noexec`: set `TMPDIR` and `XDG_CACHE_HOME` to - executable user-owned paths before install/build; -- Electron download issues: retry, or set `ELECTRON_MIRROR` and - `ELECTRON_HEADERS_URL` for your network; -- stale app tree: rebuild with `make clean build-app package`, or use - `./install.sh --fresh` for a checkout-only build; -- Computer Use readiness: run the backend `doctor` command and check - `ydotoold`, `/dev/uinput`, portal, and AT-SPI status; -- Fedora Computer Use input issue: some Fedora releases package the daemon as - `ydotool.service` rather than `ydotoold.service`; if `doctor` reports - `ydotool_socket: Permission denied`, confirm the socket is usable by users in - the `input` group; -- updater service issue: inspect - `~/.local/state/chatgpt-updater/service.log`. -- `Critical patch failures` during a local or updater rebuild: update the - checkout or installed update-builder and rebuild from the same DMG. For a - local build, inspect `dist-next/rebuild/patch-report.json` and - `chatgpt/.chatgpt-linux/build-info.json`; for an updater rebuild, inspect the - workspace `.chatgpt-linux/source-info.json` and patch report. Do not disable - critical enforcement except for a deliberately non-release emergency build. - -See [Troubleshooting](docs/usage/troubleshooting.md) for the full symptom table -and log locations. - -## Learn More - -| Goal | Go here | -| --- | --- | -| Build, run, package, install, or customize the app | [Build and Run Guide](docs/usage/build-and-run.md) | -| Understand how the DMG conversion works | [Port Architecture](docs/port-architecture.md) | -| Configure or author a port integration | [Port Integrations](port-integrations/README.md) and [Port Integration Architecture](docs/port-integrations-architecture.md) | -| Diagnose launch, CLI, webview, or updater issues | [Troubleshooting](docs/usage/troubleshooting.md) | -| Decide where to report an issue or feature request | [Support and Issue Routing](docs/usage/support-routing.md) | -| Set up or debug Linux Computer Use | [Build and Run Guide](docs/usage/build-and-run.md#linux-computer-use-controls-and-readiness) and [Troubleshooting](docs/usage/troubleshooting.md) | -| Browse all repo docs by role and task | [Documentation Index](docs/README.md) | -| Contribute a change | [Contributing](CONTRIBUTING.md) | -| Follow release notes | [Changelog](CHANGELOG.md) | -| Try the experimental rootless install path | [User-Local Desktop Integration](contrib/user-local-install/README.md) | -| Maintain packaging, launcher, or updater behavior | [Package and Runtime Maintenance](docs/maintainers/package-runtime-maintenance.md) | - -For contributors and maintenance agents, start with `AGENTS.md`. It is the -always-loaded policy surface; detailed recipes and validation matrices live in -the docs linked above. +It did not redistribute the official OpenAI app bundle. + +The [retirement record](docs/retirement.md) explains the final support boundary, +disabled maintenance automation, unresolved security risk, retained research, +and downstream M3/M4 cleanup ownership. The [documentation index](docs/README.md) +routes readers through the remaining historical material. + +## Support Boundary + +This tracker is not accepting new bug reports, feature requests, package +requests, updater requests, or compatibility work. + +- Problems that reproduce in OpenAI's official app belong with + [OpenAI Support](https://help.openai.com/). +- Codex CLI problems that reproduce independently of this retired wrapper + belong in [OpenAI's Codex repository](https://github.com/openai/codex). +- Linux conversion work that reproduces in the Linux-port upstream belongs in + [`ilysenko/codex-desktop-linux`](https://github.com/ilysenko/codex-desktop-linux), + subject to that project's own support policy. + +Do not present behavior unique to this repository as an OpenAI or Linux-port +upstream defect. + +## Unofficial Project Notice + +**ChatGPT for Linux is an unofficial community project.** It is not affiliated +with, endorsed by, sponsored by, or supported by OpenAI. OpenAI owns ChatGPT, +Codex, the official app, and the OpenAI-hosted services referenced by this +source. The repository license covers this fork's source code and packaging +work, not OpenAI software or services. Use of OpenAI software and services +remains subject to OpenAI's terms. + +The project logo is independent community artwork derived from Tux; it is not +an OpenAI mark. Tux credit: Larry Ewing and The GIMP, Garrett LeSage, and IFo +Hancroft. See the +[project-logo rights record](docs/maintainers/project-logo-rights-research.md) +for provenance and the bounded rights assessment. diff --git a/SECURITY.md b/SECURITY.md index aad5520cc..22b7efd2d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,73 +1,27 @@ # Security Policy -This repository is an unofficial community fork that layers hardening, -packaging, and runtime polish over the Linux-port upstream's synced -DMG-conversion baseline. The Linux-port upstream now develops against OpenAI's -signed Linux package; this fork remains on the official OpenAI ChatGPT DMG -until that source transition is decided explicitly. It is not affiliated with, -endorsed by, or supported by OpenAI. Security reports for this fork should -focus on the DMG conversion, package builders, generated launcher, native -packages, updater, bundled runtime helpers, local desktop integration, and -repository release workflows. - -Security guarantees made by OpenAI services, OpenAI accounts, and the official -OpenAI app bundle outside this local conversion path are outside this -repository's scope. - -## Supported Versions - -Security work targets the current `main` branch and the latest package or -release artifacts published from this fork. Older package versions are not -maintained as separate security-support lines. - -If you are using an older package build, update to the newest available package -or rebuild from current `main` before reporting an issue that may already be -fixed. - -## Reporting a Vulnerability - -Use GitHub's private vulnerability reporting flow for anything that may expose -users or package consumers. On the repository page, open **Security** and choose -**Report a vulnerability**. - -Use private reporting for issues involving: - -- updater downloads, rebuilds, state, cache, or privileged install boundaries; -- package builder inputs, package payloads, release checks, signing, or - provenance; -- generated launcher behavior, local webview serving, desktop automation, or - bundled runtime helpers; -- local file access, credentials, token handling, log redaction, or secret - exposure; -- exploitable behavior in this fork's Linux packaging or conversion workflow. - -Do not open a public issue for a suspected vulnerability before maintainers have -had a chance to triage it privately. Public issues are appropriate for ordinary -bugs, packaging failures, compatibility reports, documentation fixes, and -already-public hardening work. - -## What to Include - -Please include enough detail for maintainers to reproduce and scope the issue: - -- affected commit, package version, or artifact name; -- Linux distribution, package format, and desktop environment when relevant; -- exact commands or user actions that trigger the behavior; -- relevant logs or command output with secrets removed; -- expected impact, affected trust boundary, and any known workaround. - -## Maintainer Response - -Maintainers triage private reports on a best-effort basis through GitHub -Security Advisories. When a report is valid, maintainers coordinate the fix, -local validation, and disclosure path before public details are published when -that is practical. - -Depending on the issue, the outcome may include a private advisory, a patched -commit, updated package artifacts, release notes, maintainer documentation, or -a tracked public hardening task after sensitive details are no longer useful to -withhold. - -For maintainer-facing security workflow and current open hardening work, see -[Security Backlog](docs/maintainers/security-backlog.md). For the repository -trust-boundary model, see [Threat Model](docs/maintainers/threat-model.md). +ChatGPT for Linux is retired and unsupported. This repository has no supported +versions, no maintained packages or releases, and no security-remediation +program. It does not accept vulnerability reports or promise triage, fixes, +advisories, releases, or disclosure coordination. + +Do not submit secrets, credentials, private exploit details, or personal data +to this repository's public issue or pull-request tracker. Report a problem to +the owner that currently maintains the affected software: + +- use [OpenAI's security disclosure policy](https://openai.com/security/disclosure) + for an issue in OpenAI's official ChatGPT app, Codex, account, or hosted + services; +- use the Linux-port upstream's reporting policy for an issue that reproduces + in [`ilysenko/codex-desktop-linux`](https://github.com/ilysenko/codex-desktop-linux); + or +- use the relevant distribution package maintainer's security route for a + package-specific issue. + +The historical source, open alerts, threat model, and security backlog remain +available as evidence. They must not be interpreted as supported software or +as a commitment to remediate. See [Repository Retirement](docs/retirement.md) +for the current boundary. + +This was an unofficial community project. It is not affiliated with, endorsed +by, sponsored by, or supported by OpenAI. diff --git a/contrib/user-local-install/README.md b/contrib/user-local-install/README.md index 9f9767f82..747261935 100644 --- a/contrib/user-local-install/README.md +++ b/contrib/user-local-install/README.md @@ -1,5 +1,10 @@ # User-Local Desktop Integration +> [!WARNING] +> This installer is retained only as historical source for the retired, +> unsupported project. Do not use it as a current ChatGPT installation or +> update path. See [Repository Retirement](../../docs/retirement.md). + This folder packages this fork's user-local install layout for ChatGPT. It adds: diff --git a/docs/README.md b/docs/README.md index c5f6c2392..67feb5dd8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,102 +1,63 @@ # Documentation Index -Use this index to choose the smallest document that matches your goal. - -## Run Or Install ChatGPT - -- [Project README](../README.md) is the landing page for users and potential - users. -- [Build and Run Guide](usage/build-and-run.md) covers prerequisites, local app - generation, native package builds, package installation, NixOS, and service - commands. -- [Troubleshooting](usage/troubleshooting.md) lists common launch, CLI, webview, - package, and updater symptoms. -- [Support and Issue Routing](usage/support-routing.md) explains whether a - behavior belongs with OpenAI, the Linux-port upstream, or this fork. -- [User-Local App Integration](../contrib/user-local-install/README.md) - describes the experimental rootless install layout under XDG user paths. - -## Configure Or Extend The Port - -- [Port Integrations](../port-integrations/README.md) is the catalog and user - configuration reference for modules under `port-integrations/`. -- [Port Integration Architecture](port-integrations-architecture.md) is the - authoring reference for manifests, settings, descriptors, hooks, resources, - config resolution, and updater delivery. - -## Understand The Design - -- [Port Architecture](port-architecture.md) explains how the official OpenAI - ChatGPT DMG becomes a Linux Electron app and where replacement, patching, and - launcher orchestration fit. -- [Webview Server Evaluation](webview-server-evaluation.md) explains why the - launcher currently serves the extracted webview bundle with a local Python - HTTP server and what would need to change before replacing it. -- [Product and Visual Design](../DESIGN.md) defines the visual language, - product identity, screenshot policy, and fork-authored UI constraints. -- [Project Logo Rights and Provenance](maintainers/project-logo-rights-research.md) - records the approved asset digest, construction history, Tux attribution, - rights screen, use controls, and residual risk. - -## Maintain The Fork And Project Record - -- [Fork Divergences](maintainers/fork-divergences.md) is the canonical - inventory of intentional differences from the Linux-port upstream, including - names, paths, versioning, updater boundaries, Computer Use compatibility, and - rename-aware sync checks. -- [Fork Sync Policy](maintainers/fork-sync-policy.md) defines the current - upstream sync workflow, renamed-path reconciliation, sync ledger, local - gates, and uncertainty triage. -- [Fork Sync Ledger](maintainers/fork-sync-ledger/) records durable summaries, - special-handling notes, and follow-up decisions for broad upstream syncs. -- [Repository Rename Verification](maintainers/repository-rename-verification.md) - records the transactional `codex-app-linux` to `chatgpt-linux` cutover and - the preserved GitHub identity, redirects, automation, and trust boundaries. -- [Changelog](../CHANGELOG.md) tracks user-visible releases and packaging - behavior changes. - -## Maintain Official DMG Compatibility - -- [Official DMG Acceptance](upstream-dmg-acceptance.md) explains the policy - gate for accepting a newly observed official app bundle. -- [Official DMG Intelligence](upstream-dmg-intelligence.md) explains what the - local inspection tooling records about official releases and drift. -- [Official DMG Watchdog](upstream-dmg-watchdog.md) explains the scheduled - automation that refreshes and verifies official DMG metadata. - -## Maintain Packaging Or Runtime Behavior - -- [Package and Runtime Maintenance](maintainers/package-runtime-maintenance.md) - is the reference for source files, generated artifacts, package payloads, - launcher behavior, updater state, privileged install boundaries, versioning, - and validation. -- [README Visual Capture](maintainers/readme-visual-capture.md) defines the - maintainer process for reproducible, non-sensitive README showcase assets. -- [Launcher Performance](launcher-performance.md) explains launcher timing, - profiling, and performance acceptance. -- [Threat Model](maintainers/threat-model.md) is the repository-scoped security - model for scans and reviews. -- [Security Best Practices](maintainers/security-best-practices.md) lists - secure-by-default expectations for generated app patching, local helper - bridges, desktop capture, and hosted-service gates. -- [Security Backlog](maintainers/security-backlog.md) points to security - backlog issues and routes supply-chain review through `@codex-security`. -- [Remote Mobile Host Boundary Review](maintainers/remote-mobile-host-boundary-review.md) - records the host-state matrix for remote-control and Codex mobile review. -- [Agentic Maintenance Policy](policies/agentic-maintenance.md) explains what - belongs in tracked docs, what belongs in agent policy, and what should remain - local session evidence. - -## Pick Up Agent Work - -- Read [AGENTS.md](../AGENTS.md) first. It is the always-loaded policy surface. -- [Repository Map](agents/repository-map.md) routes source, generated, package, - updater, integration, and documentation work to the current paths. -- [Generated and Runtime Notes](agents/generated-and-runtime-notes.md) - distinguishes source-owned behavior from generated app and XDG state. -- [Backlog](backlog.md) points to open GitHub Issues for non-security and - security follow-up. -- Use the package maintenance reference for details that are too large or too - situational for `AGENTS.md`. -- Use repo-local skills under `.agents/skills/` when the task touches package - metadata, launcher behavior, updater behavior, or generated install payloads. +ChatGPT for Linux is retired and unsupported. Start with the +[repository retirement record](retirement.md) for the current producer, +support, security-risk, automation, and delayed-cleanup boundaries. + +The remaining documents describe the final maintained source state. They are +historical references, not supported install, update, troubleshooting, or +maintenance instructions. + +## Decision record + +- [Official-app parity](maintainers/research/official-app-parity-2026-08.md) + records why the validated native repackage became the settled producer. +- [Rollback-evidence retention](maintainers/research/rollback-evidence-retention-boundary-2026-08.md) + records the M3/M4 boundary for private fallback and recovery evidence. +- [Repository rename verification](maintainers/repository-rename-verification.md) + records the completed `codex-app-linux` to `chatgpt-linux` cutover. +- [Project logo rights and provenance](maintainers/project-logo-rights-research.md) + records the approved artwork, attribution, and bounded rights assessment. + +## Historical user and package references + +- [Build and run](usage/build-and-run.md) +- [Troubleshooting](usage/troubleshooting.md) +- [Former support routing](usage/support-routing.md) +- [Package and runtime maintenance](maintainers/package-runtime-maintenance.md) +- [User-local app integration](../contrib/user-local-install/README.md) +- [Port integrations](../port-integrations/README.md) + +These pages may help inspect or reproduce old source. They do not restore +support, establish current compatibility, or authorize a new package or updater +producer. + +## Historical architecture and maintenance references + +- [Port architecture](port-architecture.md) +- [Port integration architecture](port-integrations-architecture.md) +- [Fork divergences](maintainers/fork-divergences.md) +- [Fork sync policy](maintainers/fork-sync-policy.md) +- [Fork sync ledger](maintainers/fork-sync-ledger/) +- [Official DMG acceptance](upstream-dmg-acceptance.md) +- [Official DMG intelligence](upstream-dmg-intelligence.md) +- [Official DMG watchdog](upstream-dmg-watchdog.md) +- [Webview server evaluation](webview-server-evaluation.md) +- [Launcher performance](launcher-performance.md) +- [Threat model](maintainers/threat-model.md) +- [Security best practices](maintainers/security-best-practices.md) +- [Security backlog](maintainers/security-backlog.md) + +The automation described in the DMG, hash-refresh, upstream-sync, issue, and +dependency-maintenance documents is retired. Do not reinstall, dispatch, or +recreate it from these historical instructions. + +## Historical agent references + +- [AGENTS.md](../AGENTS.md) is the current archival policy and overrides old + maintenance recipes. +- [Repository map](agents/repository-map.md) describes the preserved source + layout. +- [Generated and runtime notes](agents/generated-and-runtime-notes.md) + distinguish source from generated and user-owned state. +- [Changelog](../CHANGELOG.md) preserves user-visible release history. diff --git a/docs/agents/domain.md b/docs/agents/domain.md index bc030ff61..2da8c6888 100644 --- a/docs/agents/domain.md +++ b/docs/agents/domain.md @@ -1,76 +1,24 @@ -# Domain Docs - -This is a single-context repo. Engineering skills should use one repo-wide domain context and one repo-wide ADR directory when those files exist. - -## Before exploring, read these - -- `AGENTS.md` for always-loaded repository policy. -- `docs/README.md` to choose the smallest maintained document for the task. -- `CONTEXT.md` at the repo root when it exists. -- `docs/adr/` when it exists, reading ADRs that touch the area about to change. - -If `CONTEXT.md` or `docs/adr/` does not exist, proceed silently. Do not request those files before doing ordinary work. - -## Current domain anchors - -- `docs/maintainers/fork-divergences.md` is the canonical inventory of intentional fork differences. -- `docs/maintainers/fork-sync-policy.md` defines upstream sync policy for this - fork. -- `docs/maintainers/package-runtime-maintenance.md` covers package, launcher, updater, and generated-artifact maintenance. -- `docs/maintainers/threat-model.md` describes repository trust boundaries and threat paths. -- `docs/policies/agentic-maintenance.md` describes what belongs in tracked docs, agent policy, and local session evidence. -- `docs/usage/support-routing.md` explains whether behavior belongs with - OpenAI, the Linux-port upstream, or this fork. - -## Upstream Terminology - -Use the specific term when introducing or disambiguating a surface. After the -context is clear, concise terms such as `upstream`, `DMG`, or `app bundle` are -fine. - -- `Linux-port upstream`: `ilysenko/codex-desktop-linux`, the git remote named - `upstream`, and sync work that imports that repository's Linux conversion - changes. -- `Official OpenAI ChatGPT DMG`: the OpenAI-distributed macOS app artifact used - as app-generation input. -- `Official OpenAI app bundle`: the `ChatGPT.app` bundle extracted from the DMG - and patched for Linux. -- `OpenAI-hosted services`: account, rollout, entitlement, remote-control, and - other service-side behavior outside this fork's local packaging path. - -## Port Integration Terminology - -Use `port integration` for configurable build-time modules that adapt official app -behavior or local runtime helpers to this Linux port. The implementation path is -`port-integrations/`. Checkout config uses -`port-integrations/integrations.json`; packaged installs use -`${XDG_CONFIG_HOME:-$HOME/.config}//port-integrations.json`, with -`chatgpt` as the default app id. Environment variables use -`CHATGPT_PORT_INTEGRATIONS_*`. Mention those exact names only when documenting -source paths or config APIs. - -Do not call port integrations features of Linux. They are port-authored -integrations for user-facing ChatGPT app surfaces, and this fork enables the -supported integration set by default as part of the complete local package. - -## File structure - -```text -/ -├── CONTEXT.md (when present) -├── docs/adr/ (when present) -└── docs/ - ├── README.md - ├── agents/ - ├── maintainers/ - ├── policies/ - └── usage/ -``` - -## Use the glossary vocabulary - -When `CONTEXT.md` defines a domain term, use that term in issue titles, plans, tests, and implementation notes. If the concept is missing from `CONTEXT.md`, prefer the vocabulary already used in `AGENTS.md` and the relevant maintainer doc. - -## Flag ADR conflicts - -If output contradicts an existing ADR, surface the conflict explicitly instead of silently overriding it. +# Historical Domain Record + +> [!IMPORTANT] +> This repository is retired and unsupported. Do not use this to start +> or continue planning, implementation, review, or maintenance. See +> [Repository Retirement](../retirement.md). + +This page is a non-executable historical context for the repository's final +maintained domain model. + +The repository was a local hardening and finishing fork layered over the +Linux-port upstream. It converted the official OpenAI ChatGPT DMG into native +Linux packages while preserving a local `chatgpt` identity, distro-shaped +layout, updater policy, hardening, and auditable port integrations. + +Historical terminology distinguished the Linux-port upstream, the official +OpenAI DMG and app bundle, and OpenAI-hosted services. A port integration was a +configurable build-time module under `port-integrations/`, not a feature of +Linux itself. + +The final divergence inventory, threat model, package/runtime notes, and +research records remain linked from the documentation index for provenance. +They describe the retired source; they do not authorize another sync, build, +package, or security-remediation cycle. diff --git a/docs/agents/generated-and-runtime-notes.md b/docs/agents/generated-and-runtime-notes.md index 338fc77d9..81f661e91 100644 --- a/docs/agents/generated-and-runtime-notes.md +++ b/docs/agents/generated-and-runtime-notes.md @@ -1,120 +1,34 @@ -# Generated Artifacts And Runtime Notes - -This document collects the detailed generated-output and runtime-state notes -that agents need without keeping them in the main quick-start. - -## Generated Artifacts - -- `chatgpt/` - Generated Linux app directory. Treat as build output. -- `chatgpt-next/` - Side-by-side rebuild candidate from `scripts/rebuild-candidate.sh`. Hidden - sibling `.chatgpt.candidate-*` directories are temporary transactional - install state and are removed after success or rejection by default. -- `chatgpt-*-app/` - Alternate identity app directories, such as `chatgpt-cua-lab-app/`. -- `dist/` - Native package and AppImage outputs. -- `dist/appimage.AppDir/` - Generated AppImage staging tree. -- `dist-next/rebuild/` - Rebuild candidate reports. -- `target/` - Rust build output for all workspace crates. -- `ChatGPT.dmg` - Cached official OpenAI DMG. -- `port-integrations/integrations.json` - Gitignored checkout-local `enabled`, `disabled`, and `settings` overrides. - Reviewed `defaultEnabled` values live in each repository integration's - manifest. -- `port-integrations/local/` - Gitignored user-local integration directory. -- `chatgpt/.chatgpt-linux/port-integrations-staged.json` - Staged declarative integration ownership manifest. -- `/usr/lib/chatgpt/update-builder/.chatgpt-linux/port-integrations.json` - Full resolved port integration snapshot stored in a native package's private - update-builder bundle. The copied integration tree excludes checkout-local - config files; updater rebuilds use the persistent per-user override when one - exists and otherwise preserve this snapshot. -- `~/.config/chatgpt/port-integrations.json` - Persistent packaged-install override and integration-picker selection. It can - replace the packaged snapshot for later updater rebuilds. -- `~/.config/chatgpt-updater/config.toml` - Runtime updater config. -- `~/.local/state/chatgpt-updater/state.json` - Updater state-machine persistence. -- `~/.local/state/chatgpt-updater/service.log` - Updater service log. -- `~/.cache/chatgpt-updater/` - Downloaded DMGs, rebuild workspaces, staged package artifacts, and build logs. -- `~/.cache/chatgpt/launcher.log` - Launcher log for the default app identity. -- `~/.local/state/chatgpt/app.pid` and `webview.pid` - Launcher liveness files. -- `$XDG_RUNTIME_DIR/chatgpt/launch-action.sock` - Warm-start handoff socket. - -## Runtime Notes - -- DMG extraction can warn when `7z` cannot materialize the `/Applications` - symlink. This is acceptable if a `.app` bundle was extracted successfully. -- The managed Node.js runtime is installed under - `chatgpt/resources/node-runtime/`. Override only with - `CHATGPT_MANAGED_NODE_VERSION`, `CHATGPT_MANAGED_NODE_URL`, and - `CHATGPT_MANAGED_NODE_SHA256`; the SHA must be set when overriding version or - URL. -- GUI launchers often do not inherit shell `PATH`. The generated launcher - searches common Codex CLI and `nvm` locations and respects `CODEX_CLI_PATH`. -- CLI preflight is launcher-scoped and normally best-effort. A detected npm CLI - missing its required Linux optional dependency is the exception: the launcher - performs one bounded synchronous repair and blocks Electron startup if that - repair fails or times out, because the known-broken CLI cannot serve the app. -- ASAR patches are fail-soft unless intentionally marked required. Each patch - should be idempotent and report warnings when official-app drift prevents a - needle from matching. -- Patch reports are written for installs and rebuilds. Official-DMG validation - fails only for required official-app patches that are missing or skipped. -- The Linux Computer Use backend, bundled plugin, and Linux support patches are - packaged or applied by default. The official installed-and-enabled - `computer-use@openai-bundled` plugin setting is the persistent user grant; - official account eligibility, allowed-app controls, and Codex tool approval, - sandboxing, and auto-approval policy still govern use. Host readiness proves - feasibility, not authorization. -- The `read-aloud` UI and `read-aloud-mcp` port integrations are reviewed - defaults. They do not speak automatically: playback starts only from an - explicit message action, conversation-mode action, or MCP request. Voice - model/runtime downloads are also explicit. Because `conversation-mode` - requires `read-aloud`, disable both to remove the UI backend; disable - `read-aloud-mcp` separately to remove the agent-facing plugin. -- The Linux Chrome integration stages the bundled Chrome plugin, native host, - marketplace metadata, and browser profile/native-host diagnostics for Chrome, - Brave, and Chromium. Do not fix only the user cache; patch staged bundled - resources. -- The generated launcher starts the local webview server before Electron and - verifies the expected startup markers. See - `docs/webview-server-evaluation.md` before changing the server model. -- Warm-start handoff uses a Unix-domain socket under `$XDG_RUNTIME_DIR` so - second launches can send actions to the running app. -- Native package install/removal hooks start, stop, disable, and reload the - `systemd --user` updater service on a best-effort basis. -- Failed privileged updater installs stay failed until a newer rebuild or an - explicit retry path; avoid auto-retrying every reconcile cycle. -- Manual rollback uses the last-known-good package recorded in updater state - and the same format-specific command layer as normal installs. - -For current navigation and task-specific procedures, use `docs/README.md`, -`docs/port-architecture.md`, `docs/port-integrations-architecture.md`, -`docs/usage/build-and-run.md`, and `docs/usage/troubleshooting.md` instead of -duplicating those guides here. - -## Runtime Expectations - -- `python3`, `7z`, `curl`, `unzip`, `tar`, `flock`, `make`, and `g++` are - required for `install.sh`. -- Native package builders require their format-specific tools (`dpkg-deb`, - `rpmbuild`, `makepkg`/pacman tooling, or `appimagetool`). -- `scripts/install-deps.sh` bootstraps common host dependencies. On apt-based - systems, `NODEJS_MAJOR=24 bash scripts/install-deps.sh` selects Node.js 24 - instead of the default NodeSource major. -- The packaged app still needs the Codex CLI at runtime, but launcher preflight - attempts a best-effort install/update when possible. +# Historical Generated Artifacts And Runtime Record + +> [!IMPORTANT] +> This repository is retired and unsupported. Do not use this to start +> or continue builds, runtime repair, updater work, or generated-output +> changes. See [Repository Retirement](../retirement.md). + +This page is a non-executable historical record of the final maintained +artifact and runtime boundaries. + +Generated trees included `chatgpt/`, sibling candidate app directories, +`dist/`, Rust `target/`, the cached `ChatGPT.dmg`, and updater rebuild +workspaces. Checkout-local port-integration selections and user updater state +were runtime inputs rather than durable source. + +Installed state used the `chatgpt` and `chatgpt-updater` XDG config, state, +cache, log, liveness, and runtime-socket locations. Native packages placed the +app and private rebuild support under the distro-shaped system layout recorded +in the package provenance. + +At the final maintained state, launcher startup supervised a local webview +server, warm-start handoff, Codex CLI discovery, bundled-plugin cache sync, and +Electron liveness. ASAR patches reported official-app drift, package builders +staged reviewed resources, and privileged updater actions were separated from +the unprivileged service. + +The official Computer Use plugin setting remained the persistent user grant; +account eligibility, allowed-app controls, and Codex approval and sandbox +policy remained authoritative. Read Aloud, Browser, Chrome, and other port +integration behavior remained bounded by their reviewed source contracts. + +These facts support forensic interpretation of old builds and rollback +evidence. Git history retains the commands and repair recipes; none is an +authorized maintenance route after retirement. diff --git a/docs/agents/issue-tracker.md b/docs/agents/issue-tracker.md index 4430443f1..f20d23715 100644 --- a/docs/agents/issue-tracker.md +++ b/docs/agents/issue-tracker.md @@ -1,12 +1,15 @@ # Issue Tracker: GitHub -Engineering-skill issues and PRDs for this repo currently live in GitHub Issues -for `nisavid/chatgpt-linux`. Always pass `--repo nisavid/chatgpt-linux` to the -`gh` CLI rather than relying on inferred repository identity. +Existing engineering issues and PRDs remain in GitHub Issues for +`nisavid/chatgpt-linux` as retirement evidence. The repository is closed to new +maintenance work. Skills may read or update an operator-owned closeout item +only when the active retirement task explicitly authorizes that mutation. + +Always pass `--repo nisavid/chatgpt-linux` to the `gh` CLI rather than relying +on inferred repository identity. ## Conventions -- Create an issue: `gh issue create --repo nisavid/chatgpt-linux --title "..." --body "..."` - Read an issue: `gh issue view --repo nisavid/chatgpt-linux --comments` - List issues: `gh issue list --repo nisavid/chatgpt-linux --state open --json number,title,body,labels,comments` - Comment on an issue: `gh issue comment --repo nisavid/chatgpt-linux --body "..."` @@ -15,7 +18,9 @@ for `nisavid/chatgpt-linux`. Always pass `--repo nisavid/chatgpt-linux` to the ## When a skill says "publish to the issue tracker" -Create a GitHub issue in the live repository named above. +Do not create a new issue. Retirement closeout does not open replacement +maintenance work. Report that this tracker is read-only unless an owner +initiative explicitly reverses retirement. ## When a skill says "fetch the relevant ticket" diff --git a/docs/agents/repository-map.md b/docs/agents/repository-map.md index e3e08752c..196c98097 100644 --- a/docs/agents/repository-map.md +++ b/docs/agents/repository-map.md @@ -1,355 +1,35 @@ -# Agent Repository Map - -This map keeps the detailed file ownership notes out of `AGENTS.md` while -preserving the source-of-truth routing agents need before editing. - -## Repo Orchestration - -- `install.sh` - Top-level installer entrypoint. It sources `scripts/lib/*.sh`, keeps the - high-level build sequence small, and emits `chatgpt/start.sh` from the - launcher template plus an install-time identity prelude. -- `Makefile` - Convenience targets for setup, fresh/build/install/package flows, native - package autodetection, dev side-by-side app identities, AppImage, cleanup, - and bootstrap workflows. Important targets include `setup-native`, - `bootstrap-native`, `install-native`, `update-native`, `appimage`, `package`, - and `install`, plus granular helpers (`build-app`, `build-app-fresh`, - `rebuild`, `rebuild-install`, `rebuild-next`, `build-dev-app`, `run-app`, - `run-dev-app`, `inspect-dmg`, `build-updater`, `service-enable`, - `service-status`, `check`, `test`, `clean-dist`, `clean-state`). -- `scripts/bootstrap-wizard.sh` - Guided native setup/update helper. It can discover port integrations, edit - integration config, validate integration relationships, install native packages, and - perform explicit integration-owned cleanup. -- `Cargo.toml` - Workspace root for `computer-use-linux`, `read-aloud-linux`, - `record-replay-linux`, and `updater`. -- `flake.nix` / `flake.lock` - Nix flake that pins the official DMG, Cargo dependency, and Node dependency - hashes. Use `scripts/ci/update-nix-hashes.sh` to refresh pins. -- `nix/` - Nix integration modules: `home-manager-module.nix`, `nixos-module.nix`, and - `native-modules/` rebuild support for the flake. -- `.devcontainer/devcontainer.json` / `.devcontainer/Dockerfile` - Generic build/test container with Rust, Node 22/npm, packaging tools, - `rustfmt`, and `clippy`. - -## Launcher - -- `launcher/start.sh.template` - Runtime launcher body. Edit this for webview server lifecycle, warm-start - handoff, CLI preflight, GUI prompts, URL-scheme handling, runtime Linux - integration hooks, bundled plugin cache sync, and process/liveness behavior. - Single-instance enforcement uses an `flock` launcher lock plus serialized - bootstrap around detection/spawn/`app.pid`, and a `/proc` running-app scan - filtered by `CHATGPT_LINUX_INSTANCE_ID`. -- `launcher/webview-server.py` - Standalone Python HTTP server for local webview assets, serving explicit - no-store/no-cache headers. It is started and supervised by the launcher. -- `packaging/linux/chatgpt-packaged-runtime.sh` - Native-package-only runtime helper loaded optionally by the launcher. -- `packaging/appimage/chatgpt-appimage-runtime.sh` - AppImage-only runtime helper. - -## Build Pipeline (`scripts/lib/`) - -- `install-helpers.sh` - Argument parsing, dependency checks, identity validation, install-dir - preparation, logging/color helpers, and shell quoting. -- `build-info.sh` / `build-info.js` - Build provenance capture: git commit, DMG source, official app and Electron - versions, enabled integration ids, and target context. -- `node-runtime.sh` - Managed Linux Node.js runtime download and SHA256 validation. The launcher, - Browser Use, native module rebuilds, Codex CLI flow, and updater rebuilds use - this runtime. -- `process-detection.sh` - Running-app detection used to avoid overwriting a live install. -- `dmg.sh` - Official DMG download/extraction and Electron-version detection. -- `native-modules.sh` - Linux rebuild of native modules such as `better-sqlite3` and `node-pty`, plus - Electron runtime download/cache. -- `asar-patch.sh` - Drives `scripts/patch-linux-window-ui.js` over the extracted official app. -- `webview-install.sh` - Webview asset extraction and final `chatgpt/` layout. -- `bundled-plugins.sh` - Stages bundled Browser Use, Chrome, Linux Computer Use resources, native - helper binaries, and marketplace metadata. -- `port-integrations.sh` / `port-integrations.js` - Configurable port integration framework. The JS side discovers - repository/local integrations, resolves reviewed manifest defaults plus local - `enabled`, `disabled`, and `settings` overrides, validates dependencies, - conflicts, entrypoints, resource modes, runtime hooks, and package hooks, and - exposes patch descriptors. The shell side runs integration staging in the - install pipeline. -- `package-common.sh` - Shared package-builder helpers: versioning, payload staging, permission - normalization, package hook discovery/execution, update-builder staging, and - user service helper installation. -- `linux-target-context.js` - Build-time target detection for patch descriptors from `/etc/os-release` and - environment overrides. Exposes helpers such as `matchesId()`, - `packageFormatIs()`, `packageManagerIs()`, `desktopMatches()`, and - `versionAtLeast()`. -- `patch-report.js` / `rebuild-report.sh` - Structured patch and rebuild reports used by official-app drift validation - and rebuild-candidate diagnostics. -- `patch-chrome-plugin.js` - Focused patch helper for Chrome plugin Linux compatibility. The official - bundle owns its native Linux package updater; the wrapper-updater port - integration owns local `chatgpt-updater` controls. - -## Patch Registry (`scripts/patches/`) - -- `scripts/patch-linux-window-ui.js` - ASAR patcher CLI only: argument parsing, optional JSON report writing, runner - invocation, and critical gating. Do not import internals from this file. -- `scripts/patches/core/**/patch.js` - Source of truth for shipped Linux compatibility patch descriptors. New core - patches should be descriptors under `all-linux/`, `distro/`, `package/`, or - `desktop/`. -- `scripts/patches/descriptor.js` - Descriptor factories, phase constants, and CI policy constants. Use - `mainBundlePatch`, `webviewAssetPatch`, or `extractedAppPatch`. -- `scripts/patches/engine.js` - Normalizes descriptors, checks duplicate ids, applies target/enabled - filters, executes phases, captures warnings, and records patch report - metadata. -- `scripts/patches/runner.js` - Orchestrates discovered core descriptors plus enabled port integration - descriptors. It owns `patchExtractedApp`, `patchMainBundleSource`, - `allPatchPolicies`, and `requiredPatchNamesForProfile`. -- `scripts/patches/impl/` and `scripts/patches/lib/` - Domain implementations and generic helpers used by descriptors. Do not - recreate removed compatibility barrels. -- `scripts/patches/core/README.md` - Descriptor contract. Read it before adding or moving core patches. -- `scripts/patch-linux-window-ui.test.js` - Node test suite for the patcher. -- `scripts/ci/validate-patch-report.js` - CI guard for required official-app patches. Mark a descriptor as required only - when its absence should block `official-dmg-build` CI. - -## Port Integrations (`port-integrations/`) - -`port-integrations/` is the extension boundary for configurable port integrations. -Detailed contract: `port-integrations/README.md` and -`docs/port-integrations-architecture.md`. - -- Repository integrations live under `port-integrations//`. -- User-local/private integrations live under `port-integrations/local//`; - this directory is gitignored. -- `integrations.example.json` is the committed empty override template. The - active `integrations.json` is gitignored and can add `enabled` ids, suppress - reviewed defaults with `disabled`, and provide per-integration `settings`. -- `CHATGPT_PORT_INTEGRATIONS_ROOT` and `CHATGPT_PORT_INTEGRATIONS_CONFIG` can override - integration discovery/config paths for setup and build flows. -- Integration ids use one namespace across repository and local integrations. Local - integrations cannot shadow repository integrations. -- Repository manifests may set `defaultEnabled: true` after review. Local - `disabled` entries win over both manifest defaults and `enabled` entries; - settings are retained only for integrations in the resolved enabled set. -- Every integration must have `integration.json` and `README.md`. -- Manifest `requires` and `conflicts` are validated by setup, installer, - patcher, and package builders. -- Runtime hook types are `env`, `prelaunch`, `electronArgs`, `launcher`, - `coldStart`, and `afterExit`; they are staged under - `chatgpt/.chatgpt-linux/`. -- Declarative resources and runtime hooks are tracked in - `.chatgpt-linux/port-integrations-staged.json` and removed on the next install - when their owning integration is disabled. A marker-owned cleanup hook may set - `retainWhenDisabled: true`; retained hooks must remove only owned artifacts and - must not activate the disabled integration. -- `packageHooks` run during native package staging with package/app root - environment variables. They must be idempotent and narrowly scoped. -- Native package builders copy the integration source tree, remove - checkout-local config files from that copy, and write the full resolved - `enabled`/`disabled`/`settings` snapshot to - `.chatgpt-linux/port-integrations.json` in the update-builder bundle. Updater - rebuilds prefer the persistent per-user override and otherwise preserve that - packaged snapshot. - -Use `port-integrations/` for configurable behavior whose default can change -without moving the implementation into the core patch registry. If an -integration needs more power, add a generic hook or extension point to core -rather than moving the integration itself into core. - -## Native Packaging - -- `scripts/build-deb.sh` - Builds `.deb` from an already-generated `chatgpt/`. -- `scripts/build-rpm.sh` - Builds `.rpm` from `chatgpt/`. -- `scripts/build-pacman.sh` - Builds `.pkg.tar.zst` from `chatgpt/`. -- `scripts/build-appimage.sh` - Builds an AppImage using `packaging/appimage/`. -- `packaging/linux/` - Debian control files, RPM spec, pacman `PKGBUILD.template`/install hooks, - desktop entry, icon policy, Polkit policy, packaged runtime helper, shared - user-service maintainer-script helper, and - `chatgpt-desktop-entry-doctor.sh`. -- `packaging/appimage/` - AppImage `AppRun`, desktop file, and runtime helper. - -The native package payload installs the app under `/opt/chatgpt`, the launcher -under `/usr/bin/chatgpt`, the updater under `/usr/bin/chatgpt-updater`, the -user service at `/usr/lib/systemd/user/chatgpt-updater.service`, desktop/icon -metadata under `/usr/share/`, and the update-builder bundle under -`/usr/lib/chatgpt/update-builder`. - -## Updater (`updater/`) - -- `updater/src/main.rs` / `app.rs` / `cli.rs` - Binary entrypoint, top-level dispatcher, and `clap` CLI. -- `builder.rs` - Drives the packaged update-builder bundle to rebuild packages from newer - official DMGs. -- `dmg_source.rs` - Official DMG polling, ETag cache, download, and hash verification. -- `wrapper.rs` / `wrapper_apply.rs` / `changelog.rs` / `integration_picker.rs` - Wrapper-repo self-update path, separate from the official DMG flow. -- `cache_cleanup.rs` - Cleanup of updater-managed download/rebuild workspaces under the cache dir. -- `install.rs` / `install_rollback.rs` / `rollback.rs` - Privileged package install, format-specific install/rollback commands, and - manual rollback orchestration. -- `codex_cli.rs` - Codex CLI discovery, version reads, npm-registry preflight checks, and - install/update flow used by launcher preflight. -- `state.rs` / `config.rs` - Persisted updater state and runtime config/path resolution. -- `liveness.rs` / `notify.rs` / `logging.rs` - Electron liveness, desktop notifications, and service logging. -- `test_util.rs` - Shared test helpers, including serialization of env-mutating tests. - -The updater runs unprivileged and only escalates through `pkexec` for -`install-deb`, `install-rpm`, or `install-pacman`. - -## Computer Use, Browser, Read Aloud, And Record & Replay - -- `notification-actions-linux/` - Small Rust D-Bus bridge for freedesktop notification action and close - signals. The main-process core patch uses it only for official-app - notifications that already carry actions and falls back to Electron otherwise. -- `computer-use-linux/` - Rust crate for Linux Computer Use MCP, Chrome native messaging host, and the - COSMIC helper. The backend, bundled plugin, and Linux support patches ship by - default, while official account eligibility, the persistent installed-and- - enabled plugin and allowed-app controls, and Codex approval/sandbox policy - remain authoritative. It covers input, capture, accessibility, terminal, - identity, and desktop integrations. -- `computer-use-linux/src/windowing/` - Window backend registry, target resolution, focus verification, and - backend-specific implementations. Add new compositor/window-manager support - under `windowing/backends/` and register it in `windowing/registry.rs`; - avoid backend-specific branches in `server.rs` or `diagnostics.rs`. -- `computer-use-linux/gnome-shell-extension/` - Bundled GNOME Shell extension used for exact GNOME activation. -- `plugins/openai-bundled/plugins/computer-use/` and `.../read-aloud/` - Bundled plugin manifests/resources staged into the Linux app. -- `read-aloud-linux/` - Rust MCP backend for Read Aloud support. -- `record-replay-linux/` - Rust CLI and stdio MCP backend for the optional Record & Replay Linux - demo-to-skill workflow. -- `port-integrations/read-aloud/` and `port-integrations/read-aloud-mcp/` - Reviewed default-enabled integrations for the response-level Read Aloud UI - and the agent-facing Codex MCP plugin. They remain silent until an explicit - user or agent action and do not download a voice model during install or first - launch. Because `conversation-mode` requires `read-aloud`, disable both to - remove the UI backend; disable `read-aloud-mcp` separately to remove the - agent-facing plugin. - -## User-Local Install - -`contrib/user-local-install/` is an opt-in install path for users who do not -want a system-wide native package. The daily-driver flow remains `install.sh` -plus a native `chatgpt` package and `chatgpt-updater`. - -- `install-user-local.sh` - Installs under `${XDG_DATA_HOME:-~/.local/share}/chatgpt`, creates the - public `~/.local/bin/chatgpt` launcher, and installs a user desktop entry. -- `files/.local/bin/chatgpt`, `chatgpt-check-update`, `chatgpt-update`, and - `chatgpt-version` - Launcher and private update/version maintenance payloads. Only `chatgpt` is - linked into the user's command path. -- `files/share/common.sh` - Shared helpers for installed maintenance scripts. -- `files/.local/share/applications/chatgpt.desktop` - User desktop entry installed by the user-local path. -- `files/.config/systemd/user/chatgpt-update.{service,timer}` - Optional weekly user timer. - -## Tests And CI - -- `tests/scripts_smoke.sh` - Top-level smoke suite for shell helpers, package builders, launcher template, - Electron-version detection, native modules, ASAR patches, and bundled plugin - staging. -- `tests/fixtures/create-packaged-app-fixture.sh` - Minimal fake packaged app layout for package-builder tests. -- `tests/webview_probe_equivalence.sh` - Checks the launcher's webview startup probe stays equivalent to - `launcher/webview-server.py`. -- `scripts/ci-local.sh` - Local containerized CI runner. Targets include `pr`, `all`, `core`, `deb`, - `rpm`, `pacman`, `install-deps[:image]`, `nix`, and `official-dmg`. -- `.github/workflows/` - GitHub Actions for CI, Official DMG app builds, install-deps, Cachix, Nix hash - refreshes, and Computer Use sync reminders. - -## Docs - -- `docs/README.md` - Role- and task-oriented documentation index. Start here when a task spans - more than one documentation surface. -- `README.md` - Public project overview and fast install entrypoint. -- `CONTRIBUTING.md` - Contributor expectations, including the latest-DMG-only drift policy. -- `CHANGELOG.md` - Release notes. -- `docs/port-architecture.md` - Explanation of the official DMG conversion, app generation, patching, - launcher, packaging, and updater boundaries. -- `docs/usage/build-and-run.md` - User how-to for prerequisites, local generation, native packages, Nix, - guided setup, Computer Use readiness, and service commands. -- `docs/usage/troubleshooting.md` - Symptom-oriented launch, CLI, webview, package, updater, migration, and - Computer Use diagnostics. -- `docs/usage/support-routing.md` - Routing between OpenAI, the Linux-port upstream, and this finishing fork. -- `port-integrations/README.md` - User and contributor guide to reviewed defaults, local overrides, settings, - integration lifecycle, and validation. -- `docs/port-integrations-architecture.md` - Maintainer-facing port integration architecture and manifest/hook contract. -- `docs/maintainers/package-runtime-maintenance.md` - Source, generated-output, package-payload, updater, versioning, and - validation reference. -- `docs/maintainers/fork-divergences.md` and - `docs/maintainers/fork-sync-policy.md` - Intentional local contracts and rename-aware Linux-port upstream sync policy. -- `docs/record-and-replay-linux.md` - Linux Record & Replay compatibility and tester acceptance notes. -- `docs/upstream-dmg-acceptance.md` - Shared acceptance policy for local installs, updater rebuilds, and CI. -- `docs/upstream-dmg-intelligence.md` - Protected-surface inspection and official-app drift intelligence. -- `docs/upstream-dmg-watchdog.md` - Scheduled Official DMG campaign and issue lifecycle. -- `docs/label-governance.md` - Staff-managed issue and pull request label policy. -- `docs/github-cli-auth.md` - GitHub CLI authentication behavior in app-launched shells. -- `docs/wayland-input-focus-investigation.md` and - `docs/linux-chronicle-skysight.md` - Focused investigation and integration notes for Linux-specific workflows. -- `docs/webview-server-evaluation.md` and `docs/launcher-performance.md` - Decision records for the webview server and launcher performance defaults. +# Historical Repository Map + +> [!IMPORTANT] +> This repository is retired and unsupported. Do not use this to start or +> continue editing, building, packaging, updating, syncing, or releasing. See +> [Repository Retirement](../retirement.md). + +This page is a non-executable historical context for the final source layout. + +## Final component inventory + +- `install.sh`, `launcher/`, and `scripts/lib/` formed the DMG conversion, + generated-app, launcher, runtime, and shared package pipeline. +- `scripts/patches/` and `scripts/patch-linux-window-ui.js` held the generated + app patch registry, engine, runner, implementations, and reporting gates. +- `port-integrations/` held configurable build-time modules and their staged + resource, runtime-hook, and package-hook contracts. +- `packaging/linux/`, `packaging/appimage/`, and the native package builder + scripts held distro and AppImage payload definitions. +- `updater/` held the unprivileged updater service, rebuild orchestration, + privileged installation boundary, rollback state, and CLI. +- `computer-use-linux/`, `read-aloud-linux/`, `record-replay-linux/`, and + `notification-actions-linux/` held fork-built runtime helpers. +- `plugins/openai-bundled/` held the bundled plugin manifests and resources + staged into generated apps. +- `flake.nix`, `flake.lock`, and `nix/` held the Nix build and module surface. +- `tests/`, `scripts/ci/`, and retained pull-request workflows held local and + hosted validation contracts. +- `docs/`, `README.md`, `CONTRIBUTING.md`, `SECURITY.md`, `DESIGN.md`, and + `PRODUCT.md` held user, maintainer, security, design, and product records. + +The source tree and its Git history preserve the detailed ownership and +implementation map. This abbreviated record exists only to interpret old +commits, build evidence, package provenance, and rollback material. It does +not select files for new work or describe a supported install or update route. diff --git a/docs/agents/validation-playbook.md b/docs/agents/validation-playbook.md index d30ab0966..873e39a7c 100644 --- a/docs/agents/validation-playbook.md +++ b/docs/agents/validation-playbook.md @@ -1,8 +1,12 @@ # Agent Validation Playbook -Run the smallest validation set that matches the touched surface, then broaden -when the change crosses package formats, launcher/runtime behavior, updater -state, or patch drift handling. +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [Repository Retirement](../retirement.md). + +This playbook preserves the validation commands used before retirement. Use it +only to interpret historical changes or an owner-authorized closeout task. ## Shell, Launcher, And Package Scripts diff --git a/docs/backlog.md b/docs/backlog.md index 6d458f397..66b8ff133 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -1,11 +1,15 @@ # Backlog -Open follow-up work now lives in GitHub Issues. +> [!NOTE] +> The maintenance backlog is closed to new work. Existing items are retained +> for retirement disposition and historical evidence; unresolved security +> items remain unresolved retired risk. See [Repository Retirement](retirement.md). + +The historical backlog remains visible in GitHub Issues for retirement +disposition and provenance: - [All backlog issues](https://github.com/nisavid/chatgpt-linux/issues?q=is%3Aissue%20is%3Aopen%20label%3Abacklog) - [Maintainer-facing backlog issues](https://github.com/nisavid/chatgpt-linux/issues?q=is%3Aissue%20is%3Aopen%20label%3Abacklog%20label%3Aaudience%2Fmaintainer) - [Security backlog index](maintainers/security-backlog.md) -Keep new durable work items in GitHub Issues with the `backlog` label instead -of adding task detail here. Use this file only as the repository-local pointer -to the active queue. +Do not add new backlog items or treat these searches as a work queue. diff --git a/docs/github-cli-auth.md b/docs/github-cli-auth.md index 8091b28b1..e94e0d6fe 100644 --- a/docs/github-cli-auth.md +++ b/docs/github-cli-auth.md @@ -1,5 +1,10 @@ # GitHub CLI auth in app-launched shells +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [Repository Retirement](retirement.md). + ChatGPT can launch successfully while shell commands inside the app still see a different desktop session environment than a normal terminal. One common symptom is that `gh auth status` works in the user's terminal, but commands run diff --git a/docs/label-governance.md b/docs/label-governance.md index f0a6daf3d..d9163bdff 100644 --- a/docs/label-governance.md +++ b/docs/label-governance.md @@ -1,21 +1,23 @@ # Issue and pull request label governance -Repository labels are a maintainer-owned triage layer. They give people a -quick view of what an item is, where it belongs, what is holding it up, and how -carefully a pull request must be reviewed. They also give repository -automation a small, deterministic vocabulary without exposing internal job -states in the issue and pull request lists. +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [Repository Retirement](retirement.md). + +Before retirement, repository labels formed a maintainer-owned triage layer. +This document preserves that classification and migration contract for the +historical tracker record. [`.github/labels.json`](../.github/labels.json) is the machine-readable source of truth for names, colors, descriptions, groups, migrations, and retirements. This document defines how those labels are selected and who may change them. -## Authority +## Historical authority -Label decisions belong to the repository owner and collaborators who have the -GitHub permission required to manage labels. Contributors without that -permission provide evidence; they do not choose, apply, remove, or rename -labels for their own work. +Before retirement, label decisions belonged to the repository owner and +collaborators with label-management permission. Contributors supplied evidence +but did not choose, apply, remove, or rename labels for their own work. The same boundary applies to coding agents and automation: @@ -24,12 +26,12 @@ The same boundary applies to coding agents and automation: | Reporter or pull request author without label permission | Supply reproduction details, scope, affected paths, and validation results. Do not self-classify. | | Maintainer or authorized collaborator | Make the final classification and apply or remove labels. | | Agent without delegated label authority | Read labels and native GitHub state. It may propose a classification to authorized staff, but must not mutate labels. | -| Authorized repository workflow or agent operation | Apply a reviewed deterministic plan from the trusted default branch, with the permissions and confirmation required by the manual workflow. | +| Authorized repository workflow or agent operation | Applied a reviewed deterministic plan from the trusted default branch, with the permissions and confirmation required by the former manual workflow. | -A proposal from an agent is not a repository decision. The label changes only -when authorized staff accepts it or explicitly runs the staff-controlled -workflow. Authors must never be asked to add a label themselves. An unlabeled -new item is awaiting triage, not rejected. +This authority model is retained only to interpret the historical tracker. The +retired repository has no current label workflow or maintenance-triage intake. +Owner-directed closeout follows `AGENTS.md` and +[Issue Tracker](agents/issue-tracker.md). ## Classification contract @@ -185,34 +187,21 @@ public label. `resolution: duplicate` is applied only after an authorized human or explicitly authorized staff operation verifies and links the canonical item. -## Agent and automation rules - -An agent classifying an item must read the body, linked discussion, changed -files, checks, review state, and the current label policy. A title alone is not -enough. When evidence is missing, preserve that uncertainty with -`status: needs triage`, `status: needs information`, or -`status: needs reproduction`; do not guess a stronger state. - -Without explicit delegated staff authority, the output is a proposal only. -With delegated authority, the operation must still use the trusted manual -workflow or the repository script, show its plan first, and keep the typed -confirmation boundary. A fork pull request never receives a write token for -label governance. - -The `workflow: manual only` label overrides every item-specific automation -path. The only exception is an owner-approved catalog migration declared in -`.github/labels.json`; it may rename a label or transfer the same existing -classification, but it may not infer a new classification or change the item -itself. A low-risk classification does not authorize automatic merge. Branch -protection, review requirements, and the contributor workflow in -`CONTRIBUTING.md` remain in force. - -Repository-owned issue producers must read their labels from the policy and -apply a complete deterministic classification. The Computer Use sync reminder -and official-DMG drift reconciler follow this rule. Existing item automation, -including the contributor pull request limit, must inspect -`workflow: manual only` before any comment, edit, classification, close, or -merge operation and leave that item for staff. +## Historical agent and automation rules + +Before retirement, an agent proposing a classification read the body, linked +discussion, changed files, checks, review state, and label policy rather than +classifying from a title alone. Missing evidence remained explicit through +triage, information, or reproduction states. + +The former manual label workflow, Computer Use reminder, official-DMG issue +reconciler, and contributor pull-request limiter are removed. The retained +label script is historical source and is not an authorized mutation path. + +The `workflow: manual only` rules and deterministic producer classifications +below explain prior tracker state. They do not authorize restoring deleted +automation, accepting new maintenance work, or mutating closeout items outside +the owner-directed retirement process. ## Color system @@ -231,66 +220,13 @@ scannable: Color never carries meaning by itself. Every label has an English name and a short description for accessibility, search, and API consumers. -## Safe synchronization and migration - -The manual [Manage repository labels](../.github/workflows/manage-labels.yml) -workflow is the only repository-supplied bulk mutation path. It checks out the -trusted default branch even if another ref is selected in the dispatch UI. -Only a user with the repository permission required to run the workflow can -start it. - -The migration is intentionally split: - -1. Merge the reviewed policy, documentation, script, tests, and workflow. -2. Update or disable any external automation that still writes retired names. - The committed Computer Use and official-DMG issue producers read their - classifications from the policy. -3. Run `plan`. It is read-only and needs no confirmation text. - It also reports open items whose migrated labels still need a required - staff classification; these are triage notices, not inferred labels. -4. Run `apply` with confirmation `APPLY`. This creates or updates desired - labels, renames the primary legacy labels, and transfers associations from - secondary legacy labels. It does not delete labels outside the explicit - retirement list. -5. Resolve every open-item retirement blocker. An old label can be removed - from an open item only when its governed replacement is already attached; - labels without a direct replacement must be reviewed by staff first. -6. Run `retire` with confirmation `RETIRE`. The workflow captures and uploads - a pre-change snapshot before deletion. It aborts if the live labels or their - associations change after that snapshot. - -The script is idempotent. A failed apply can be rerun: completed renames are -recognized, existing desired labels are updated in place, and already migrated -associations are skipped. Convergence stops before its first write if projected -labels would violate an exclusive group or apply to the wrong item type. -Open migrated items with an incomplete required classification are listed for -staff triage instead of being guessed by the migration. -Retirement is fail-closed; it checks every blocker before deleting the first -label. An interrupted retirement can resume from the same snapshot: already -absent retired labels count as completed, while every remaining source and -migration target must still match the snapshot. Unknown labels are never -pruned. - -For a local read-only plan: - -```bash -GITHUB_TOKEN="$(gh auth token)" node scripts/ci/manage-labels.js \ - --repo nisavid/chatgpt-linux -``` - -Keep tokens in the environment, not in command arguments. For an emergency -non-destructive restore, download a workflow snapshot and run: - -```bash -GITHUB_TOKEN="$(gh auth token)" node scripts/ci/manage-labels.js \ - --repo nisavid/chatgpt-linux \ - --restore /path/to/repository-labels-before.json \ - --confirm RESTORE -``` - -Restore recreates only labels in the policy's explicit retirement list and -reapplies their saved issue and pull request associations. It does not remove -the new taxonomy or alter native GitHub state. +## Historical synchronization and migration + +The removed `manage-labels` workflow was the repository's only supplied bulk +mutation path. Its guarded plan/apply/retire sequence, snapshots, fail-closed +checks, and restore behavior remain available in Git history. Retirement does +not authorize running the retained script directly, restoring that workflow, +or starting another label migration. ## Examples diff --git a/docs/maintainers/fork-divergences.md b/docs/maintainers/fork-divergences.md index a32006989..a33bfacd2 100644 --- a/docs/maintainers/fork-divergences.md +++ b/docs/maintainers/fork-divergences.md @@ -1,17 +1,23 @@ # Fork Divergences +> [!NOTE] +> This inventory is a non-executable historical record of the final maintained +> divergence state. The repository is retired and unsupported. Do not use it to +> start or continue sync, build, package, release, or security work. See +> [Repository Retirement](../retirement.md). + This reference records the intentional differences between this fork and the last synced ref from the Linux-port upstream. In this document, `upstream` means -that remote unless a sentence names another surface. Use this inventory during -upstream syncs to preserve local contracts and keep divergence claims grounded -in the synced baseline. Treat these differences as a finishing layer: upstream -owns the primary Linux app conversion and much of the runtime support, while -this fork preserves local names, paths, updater policy, hardening, security -review, packaging polish, and maintainer policy. +that remote unless a sentence names another surface. The inventory was used +during upstream syncs to preserve local contracts and keep divergence claims +grounded in the synced baseline. These differences formed a finishing layer: +upstream owned the primary Linux app conversion and much of the runtime +support, while this fork preserved local names, paths, updater policy, +hardening, security review, packaging polish, and maintainer policy. ## Upstream Terminology -Use the same terms as `AGENTS.md`: +The final maintained documentation used these terms from `AGENTS.md`: - `Linux-port upstream`: `ilysenko/codex-desktop-linux`, the git remote named `upstream`, and sync work that imports that repository's Linux conversion @@ -23,61 +29,44 @@ Use the same terms as `AGENTS.md`: - `OpenAI-hosted services`: account, rollout, entitlement, remote-control, and other service-side behavior outside this fork's local packaging path. -Use the specific term when a reader could confuse the Linux-port upstream with -the official OpenAI app, DMG, app bundle, or hosted services. Once the surface -is clear, concise terms such as `upstream`, `DMG`, or `app bundle` are fine. +Specific terms distinguished the Linux-port upstream from the official OpenAI +app, DMG, app bundle, and hosted services. Once a surface was clear, concise +terms such as `upstream`, `DMG`, or `app bundle` appeared in the record. -The current comparison baseline is upstream commit +The final comparison baseline is upstream commit `efe491761d9075341fe79f564631a6dd9aafd291` (2026-07-30). Claims below describe the current tree's diff against that baseline, with current source files taking precedence over generated output. -## Post-Baseline Source Decision +## Final Source Decision After this baseline, the Linux-port upstream switched its app input to OpenAI's -signed Linux APT package. This fork intentionally remains a DMG-based -maintenance fallback while that official Linux app is evaluated. Both native -packages own the `chatgpt` identity and are mutually exclusive on one host; -follow the accepted switch and rollback procedure in -[Package and Runtime Maintenance](package-runtime-maintenance.md#official-app-evaluation-switch). -Do not import the source transition or claim co-installation without a new -explicit decision covering source, package ownership, conflicts, upgrades, and -update authority together. - -## Sync Review Rule - -For each upstream sync: - -1. Read this inventory before editing or resolving conflicts. -2. Compare incoming changes against every divergence area below. -3. Preserve local names, paths, versioning, updater boundaries, package shape, - and security gates unless the PR intentionally changes this policy. -4. Describe each divergence as the current local finishing-layer delta against - the synced upstream baseline: naming, layout, hardening, packaging, - compatibility, security review, or documentation. -5. Escalate uncertain conflicts to the operator when the session allows. If - escalation is unavailable or the operator requested an uninterrupted run, - record a durable, discoverable follow-up where the escalation would have - happened, and link it from the sync ledger. -6. Run the local build gate before pushing when generated-app, package, updater - rebuild, or bundled runtime behavior is touched. The minimum gate is - `make build-app` or `./install.sh` after the DMG freshness check; package - payload changes also need the relevant package builder, and release workflow - changes also need the relevant release-gate command. +signed Linux APT package. This fork remained a DMG-based maintenance fallback +until the signed Linux package was accepted as its successor. Both native +packages owned the `chatgpt` identity and were mutually exclusive on one host. +The accepted switch, rollback evidence, and delayed cleanup boundary are +recorded in [Repository Retirement](../retirement.md). + +## Historical Sync Review Record + +Before retirement, sync reviews compared incoming changes with every +divergence area below. They preserved local naming, layout, versioning, updater, +package, and security boundaries; recorded uncertain conflicts in the sync +ledger; and bound generated-app or package changes to local build evidence. +This record no longer defines a sync procedure. The layout rules for this fork follow, in order, the XDG Base Directory Specification, the Filesystem Hierarchy Standard, and common distro conventions for modern Electron-style app bundles. -## Current Local Rename And Compatibility Map +## Final Maintained Rename And Compatibility Map -Use this map during upstream syncs. If upstream edits an old path or token, -reconcile the change into the current local path or token before deleting the -old target from the merge result. +This map recorded the rename and compatibility relationships applied during +the final maintained syncs. It is retained for provenance only. -| Old target or token | Current local target or token | Source and sync relevance | +| Old target or token | Final local target or token | Historical sync relevance | | --- | --- | --- | -| Former repository slug `nisavid/codex-app-linux` | Canonical repository `nisavid/chatgpt-linux` | The in-place rename preserved repository and fork identity. GitHub redirects the former web and Git endpoints; use only the canonical slug for new operations and durable links. | +| Former repository slug `nisavid/codex-app-linux` | Canonical repository `nisavid/chatgpt-linux` | The in-place rename preserved repository and fork identity. New operations and durable links used the canonical slug. | | Local package, command, desktop, and app/XDG identity `codex-app` | `chatgpt` | Native package metadata replaces/conflicts with the old package, but no executable, desktop, service, or filesystem shim is installed. Wrapper-owned XDG directories move through the journaled state migration. | | Local updater crate, command, service, and XDG identity `codex-app-updater` | `chatgpt-updater` | Package lifecycle hooks disable the old service and enable the canonical service when policy permits. Updater config, state, and cache move through the same migration; no service alias is installed. | | Generated metadata root `.codex-linux/` and local setting keys beginning `codex-linux-` | `.chatgpt-linux/` and `chatgpt-linux-` | The migration rewrites known wrapper-owned text files and moves the CLI quarantine directory. Generated output uses only canonical names. | @@ -85,25 +74,25 @@ old target from the merge result. | Port-owned `CODEX_*` environment variables | Corresponding `CHATGPT_*` names | Old port-owned names are rejected or ignored rather than treated as compatibility aliases. Inherited OpenAI Codex CLI, app-server, plugin, browser-use, Node REPL, bundle, skill, and protocol variables retain `CODEX_*`. | | Port-owned `CODEX_MICRO_NODE_HID_ARCHIVE` | `CHATGPT_MICRO_NODE_HID_ARCHIVE` | The Nix build override belongs to the Linux-port integration, not the official Codex Micro protocol. Old installer or launcher input is rejected. | | Port-owned `CODEX_PRIMARY_RUNTIME_ROOT` and `CODEX_RUNTIME_ROOT` | `CHATGPT_PRIMARY_RUNTIME_ROOT` and `CHATGPT_RUNTIME_ROOT` | The Nix launcher overrides were introduced by the Linux port. The underlying OpenAI runtime artifact and `codex-runtimes/codex-primary-runtime` cache path keep their upstream names. | -| `.github/workflows/upstream-build-app.yml` | `.github/workflows/official-dmg-build-app.yml` | Exists in `upstream/main`; port incoming workflow edits here. | -| `updater/src/upstream.rs` | `updater/src/dmg_source.rs` | Exists in `upstream/main`; port incoming updater source edits here. | -| patch `ciPolicy: "required-upstream"` | `ciPolicy: "required-official-dmg"`; the old value is accepted only as a legacy alias | Exists in `upstream/main`; port incoming required-patch policy edits to the current token unless intentionally preserving compatibility aliases. | -| patch-report profile `upstream-build` | `official-dmg-build`; the old profile is accepted only as a legacy alias | Exists in `upstream/main`; port incoming validation-profile edits to the current profile name. | -| CI job or local CI target `upstream` for official DMG validation | `official-dmg`; the old target is accepted only as a legacy alias | Exists in `upstream/main`; port incoming official DMG validation job/target changes to the current name. | -| `UPSTREAM_DMG_URL`, `UPSTREAM_DMG_PATH`, `UPSTREAM_DMG_CACHE_HIT` | `OFFICIAL_DMG_URL`, `OFFICIAL_DMG_PATH`, `OFFICIAL_DMG_CACHE_HIT`; old variables are legacy aliases | Exists in `upstream/main`; port incoming official DMG environment changes to the current variables and preserve legacy fallbacks only for compatibility. | -| Port integration hook `CODEX_UPSTREAM_APP_DIR` | `CHATGPT_OFFICIAL_APP_DIR`; the old port-owned variable is obsolete | Exists in `upstream/main`; port incoming stage-hook environment changes to the current variable; do not restore the obsolete port-owned alias. | -| Make target `inspect-upstream` | `inspect-dmg`; the old target is a legacy alias | Exists in `upstream/main`; port incoming inspect-target behavior to `inspect-dmg` and keep the old target as an alias only while useful. | -| `packaging/appimage/codex-desktop.desktop` | `packaging/appimage/chatgpt.desktop` | Exists in `upstream/main`; port incoming AppImage desktop-entry edits to the current local AppImage desktop entry. | -| `packaging/linux/codex-desktop.spec`, `packaging/linux/codex-desktop.install`, `packaging/linux/codex-desktop.desktop`, and `packaging/linux/codex-desktop-entry-doctor.sh` | `packaging/linux/chatgpt.spec`, `packaging/linux/chatgpt.install`, `packaging/linux/chatgpt.desktop`, and `packaging/linux/chatgpt-desktop-entry-doctor.sh` | Exists in `upstream/main`; port incoming native package identity and desktop-integration edits to the current local package files. | -| `packaging/linux/codex-update-manager.service`, `packaging/linux/codex-update-manager-user-service.sh`, `packaging/linux/codex-update-manager.postinst`, `packaging/linux/codex-update-manager.postrm`, and `packaging/linux/codex-update-manager.prerm` | `packaging/linux/chatgpt-updater.service`, `packaging/linux/chatgpt-updater-user-service.sh`, `packaging/linux/chatgpt-updater.postinst`, `packaging/linux/chatgpt-updater.postrm`, and `packaging/linux/chatgpt-updater.prerm` | Exists in `upstream/main`; port incoming updater service and maintainer-script edits under the local updater identity. | -| `packaging/linux/com.github.ilysenko.codex-desktop-linux.update.policy` | `packaging/linux/com.github.nisavid.chatgpt.update.policy` | Exists in `upstream/main`; port incoming privileged install policy edits to the local policy file and preserve the local action identifiers. | -| `contrib/user-local-install/files/.config/systemd/user/codex-desktop-update.service`, `contrib/user-local-install/files/.config/systemd/user/codex-desktop-update.timer`, `contrib/user-local-install/files/.local/bin/codex-desktop*`, `contrib/user-local-install/files/.local/share/applications/codex-desktop.desktop`, and `contrib/user-local-install/files/.local/lib/codex-desktop-linux/common.sh` | `contrib/user-local-install/files/.config/systemd/user/chatgpt-update.service`, `contrib/user-local-install/files/.config/systemd/user/chatgpt-update.timer`, `contrib/user-local-install/files/.local/bin/chatgpt*`, `contrib/user-local-install/files/.local/share/applications/chatgpt.desktop`, and `contrib/user-local-install/files/share/common.sh` | Exists in `upstream/main`; port incoming user-local install experiment edits to the current local names and layout. | -| `linux-features/` | `port-integrations/`; the old root is accepted only as a legacy override target | Exists in the Linux-port upstream's old registry naming; port incoming registry edits to `port-integrations/`. | -| `linux-features/*/feature.json` | `port-integrations/*/integration.json`; old manifests are accepted only for legacy roots | Exists in the Linux-port upstream's old registry naming; port incoming manifest edits to the current manifest path. | -| `linux-features/features.example.json` and `linux-features/features.json` | `port-integrations/integrations.example.json` and `port-integrations/integrations.json`; old names are compatibility fallbacks | Exists in the Linux-port upstream's old registry naming; port incoming config-shape changes to the current config names. | -| `scripts/lib/linux-features.js` and `scripts/lib/linux-features.sh` | `scripts/lib/port-integrations.js` and `scripts/lib/port-integrations.sh` | Exists in the Linux-port upstream's old registry naming; port incoming helper changes to the current helper names. | -| `CHATGPT_LINUX_FEATURES_ROOT`, `CHATGPT_LINUX_FEATURES_CONFIG`, `CHATGPT_LINUX_FEATURES`, `CHATGPT_LINUX_DISABLE_FEATURES`, `CHATGPT_LINUX_FEATURES_DIR`, and `CHATGPT_LINUX_FEATURE_HOOK_PHASE` | `CHATGPT_PORT_INTEGRATIONS_ROOT`, `CHATGPT_PORT_INTEGRATIONS_CONFIG`, `CHATGPT_PORT_INTEGRATIONS`, `CHATGPT_DISABLE_PORT_INTEGRATIONS`, `CHATGPT_PORT_INTEGRATIONS_DIR`, and `CHATGPT_PORT_INTEGRATION_HOOK_PHASE`; old variables are rejected with the exact current replacement | Exists in the Linux-port upstream's old registry naming; port incoming environment handling to the current variables without compatibility aliases. | -| `CHATGPT_BOOTSTRAP_CLEANUP_FEATURES` | `CHATGPT_BOOTSTRAP_CLEANUP_INTEGRATIONS`; the old variable is rejected with the exact current replacement | Exists in earlier local setup helper behavior; use only the current variable in source, docs, and normal tests. | +| `.github/workflows/upstream-build-app.yml` | `.github/workflows/official-dmg-build-app.yml` | Final syncs ported incoming workflow edits here. | +| `updater/src/upstream.rs` | `updater/src/dmg_source.rs` | Final syncs ported incoming updater source edits here. | +| patch `ciPolicy: "required-upstream"` | `ciPolicy: "required-official-dmg"`; the old value is accepted only as a legacy alias | Final syncs ported incoming required-patch policy edits to the current token unless intentionally preserving compatibility aliases. | +| patch-report profile `upstream-build` | `official-dmg-build`; the old profile is accepted only as a legacy alias | Final syncs ported incoming validation-profile edits to the current profile name. | +| CI job or local CI target `upstream` for official DMG validation | `official-dmg`; the old target is accepted only as a legacy alias | Final syncs ported incoming official DMG validation job/target changes to the current name. | +| `UPSTREAM_DMG_URL`, `UPSTREAM_DMG_PATH`, `UPSTREAM_DMG_CACHE_HIT` | `OFFICIAL_DMG_URL`, `OFFICIAL_DMG_PATH`, `OFFICIAL_DMG_CACHE_HIT`; old variables are legacy aliases | Final syncs ported incoming official DMG environment changes to the current variables and preserved legacy fallbacks only for compatibility. | +| Port integration hook `CODEX_UPSTREAM_APP_DIR` | `CHATGPT_OFFICIAL_APP_DIR`; the old port-owned variable is obsolete | Final syncs ported stage-hook environment changes to the current variable; the obsolete alias remained absent. | +| Make target `inspect-upstream` | `inspect-dmg`; the old target is a legacy alias | Final syncs ported inspect-target behavior to `inspect-dmg`; the old target remained only as a legacy alias. | +| `packaging/appimage/codex-desktop.desktop` | `packaging/appimage/chatgpt.desktop` | Final syncs ported incoming AppImage desktop-entry edits to the current local AppImage desktop entry. | +| `packaging/linux/codex-desktop.spec`, `packaging/linux/codex-desktop.install`, `packaging/linux/codex-desktop.desktop`, and `packaging/linux/codex-desktop-entry-doctor.sh` | `packaging/linux/chatgpt.spec`, `packaging/linux/chatgpt.install`, `packaging/linux/chatgpt.desktop`, and `packaging/linux/chatgpt-desktop-entry-doctor.sh` | Final syncs ported incoming native package identity and desktop-integration edits to the current local package files. | +| `packaging/linux/codex-update-manager.service`, `packaging/linux/codex-update-manager-user-service.sh`, `packaging/linux/codex-update-manager.postinst`, `packaging/linux/codex-update-manager.postrm`, and `packaging/linux/codex-update-manager.prerm` | `packaging/linux/chatgpt-updater.service`, `packaging/linux/chatgpt-updater-user-service.sh`, `packaging/linux/chatgpt-updater.postinst`, `packaging/linux/chatgpt-updater.postrm`, and `packaging/linux/chatgpt-updater.prerm` | Final syncs ported incoming updater service and maintainer-script edits under the local updater identity. | +| `packaging/linux/com.github.ilysenko.codex-desktop-linux.update.policy` | `packaging/linux/com.github.nisavid.chatgpt.update.policy` | Final syncs ported incoming privileged install policy edits to the local policy file and preserved the local action identifiers. | +| `contrib/user-local-install/files/.config/systemd/user/codex-desktop-update.service`, `contrib/user-local-install/files/.config/systemd/user/codex-desktop-update.timer`, `contrib/user-local-install/files/.local/bin/codex-desktop*`, `contrib/user-local-install/files/.local/share/applications/codex-desktop.desktop`, and `contrib/user-local-install/files/.local/lib/codex-desktop-linux/common.sh` | `contrib/user-local-install/files/.config/systemd/user/chatgpt-update.service`, `contrib/user-local-install/files/.config/systemd/user/chatgpt-update.timer`, `contrib/user-local-install/files/.local/bin/chatgpt*`, `contrib/user-local-install/files/.local/share/applications/chatgpt.desktop`, and `contrib/user-local-install/files/share/common.sh` | Final syncs ported incoming user-local install experiment edits to the current local names and layout. | +| `linux-features/` | `port-integrations/`; the old root is accepted only as a legacy override target | Final syncs ported incoming registry edits to `port-integrations/`. | +| `linux-features/*/feature.json` | `port-integrations/*/integration.json`; old manifests are accepted only for legacy roots | Final syncs ported incoming manifest edits to the current manifest path. | +| `linux-features/features.example.json` and `linux-features/features.json` | `port-integrations/integrations.example.json` and `port-integrations/integrations.json`; old names are compatibility fallbacks | Final syncs ported incoming config-shape changes to the current config names. | +| `scripts/lib/linux-features.js` and `scripts/lib/linux-features.sh` | `scripts/lib/port-integrations.js` and `scripts/lib/port-integrations.sh` | Final syncs ported incoming helper changes to the current helper names. | +| `CHATGPT_LINUX_FEATURES_ROOT`, `CHATGPT_LINUX_FEATURES_CONFIG`, `CHATGPT_LINUX_FEATURES`, `CHATGPT_LINUX_DISABLE_FEATURES`, `CHATGPT_LINUX_FEATURES_DIR`, and `CHATGPT_LINUX_FEATURE_HOOK_PHASE` | `CHATGPT_PORT_INTEGRATIONS_ROOT`, `CHATGPT_PORT_INTEGRATIONS_CONFIG`, `CHATGPT_PORT_INTEGRATIONS`, `CHATGPT_DISABLE_PORT_INTEGRATIONS`, `CHATGPT_PORT_INTEGRATIONS_DIR`, and `CHATGPT_PORT_INTEGRATION_HOOK_PHASE`; old variables are rejected with the exact current replacement | Final syncs ported incoming environment handling to the current variables without compatibility aliases. | +| `CHATGPT_BOOTSTRAP_CLEANUP_FEATURES` | `CHATGPT_BOOTSTRAP_CLEANUP_INTEGRATIONS`; the old variable is rejected with the exact current replacement | Final source, docs, and normal tests used only the current variable. | ## Divergence Inventory @@ -119,11 +108,11 @@ binary, service, config, state, cache, and logs as `chatgpt-updater`. model come from upstream. The fork-specific contract is the local identity and compatibility handling around that inherited model. -**Why it matters:** These names are user-visible package and runtime contracts. +**Why it mattered:** These names are user-visible package and runtime contracts. Adopting upstream names during a sync breaks upgrade paths, service state, desktop integration, docs, and user commands. -**Current paths:** `Cargo.toml`, `updater/Cargo.toml`, `Makefile`, +**Final maintained paths:** `Cargo.toml`, `updater/Cargo.toml`, `Makefile`, `install.sh`, `launcher/start.sh.template`, `launcher/state-migration.py`, `packaging/linux/`, `scripts/build-deb.sh`, `scripts/build-rpm.sh`, `scripts/build-pacman.sh`, `scripts/lib/package-common.sh`, `updater/`, @@ -139,12 +128,11 @@ quarantine directories. The migration is journaled and resumable, discards only known volatile runtime files, fails closed on collisions and unsafe path shapes, and supports `chatgpt migrate-state --reverse`. -**Preservation checks:** Search user-facing docs, package metadata, desktop -entries, services, updater paths, and launcher commands for upstream or former -local names. Keep `codex-app`, `codex-desktop`, `codex-app-updater`, and -`codex-update-manager` only in package transition metadata, migration logic, -tests of legacy input, or explicit history/compatibility prose. Keep inherited -OpenAI Codex interfaces unchanged. +**Former preservation evidence:** Reviews searched user-facing docs, package +metadata, desktop entries, services, updater paths, and launcher commands for +former local names. Those names remained only in transition metadata, +migration logic, legacy-input tests, or explicit history; inherited OpenAI +Codex interfaces remained unchanged. ### 2. Linux Filesystem Layout And Package Payload Contract @@ -158,20 +146,20 @@ under XDG base directories. The update-builder bundle is deliberately under update-builder payload. This fork changes the installed names and payload placement, and keeps those choices aligned with XDG/FHS criteria. -**Why it matters:** This layout matches distro expectations for package-managed +**Why it mattered:** This layout matches distro expectations for package-managed Electron app bundles and keeps mutable user state out of system package roots. -**Current paths:** `packaging/linux/PKGBUILD.template`, +**Final maintained paths:** `packaging/linux/PKGBUILD.template`, `packaging/linux/control`, `packaging/linux/chatgpt.spec`, `packaging/linux/chatgpt.install`, Debian/RPM maintainer scripts, `packaging/linux/chatgpt-packaged-runtime.sh`, `scripts/lib/package-common.sh`, `launcher/start.sh.template`, `updater/src/config.rs`, `updater/src/app.rs`, `updater/src/builder.rs`, `contrib/user-local-install/`. -**Preservation checks:** Inspect package file lists and source templates for -`/opt/chatgpt`, `/usr/lib/chatgpt`, `/usr/bin/chatgpt`, -`/usr/bin/chatgpt-updater`, and XDG paths. Do not adopt `~/.local/opt`, -`/opt/codex-desktop`, or upstream support-bundle paths during a sync. +**Former preservation evidence:** Package file lists and source templates were +checked for `/opt/chatgpt`, `/usr/lib/chatgpt`, `/usr/bin/chatgpt`, +`/usr/bin/chatgpt-updater`, and XDG paths. The final payload did not adopt +`~/.local/opt`, `/opt/codex-desktop`, or upstream support-bundle paths. ### 3. Package Versioning From The OpenAI DMG Bundle @@ -185,18 +173,19 @@ candidates from official OpenAI ChatGPT DMG metadata. This fork changes native package versioning and updater comparison helpers so package upgrades track the DMG-contained app version. -**Why it matters:** Package upgrades, updater comparisons, release notes, and -user expectations should track the official app version, not local build time. +**Why it mattered:** Package upgrades, updater comparisons, release notes, and +user expectations tracked the official app version rather than local build +time. -**Current paths:** `install.sh`, `scripts/lib/dmg.sh`, +**Final maintained paths:** `install.sh`, `scripts/lib/dmg.sh`, `scripts/lib/package-common.sh`, package builders, `updater/src/app.rs`, `updater/src/builder.rs`, `updater/src/package_version.rs`, `updater/src/dmg_source.rs`, `README.md`, `docs/usage/build-and-run.md`, `tests/scripts_smoke.sh`. -**Preservation checks:** Run `make help` and package docs checks to ensure -plain `make deb`, `make rpm`, and `make pacman` are the normal path. Keep -`PACKAGE_VERSION=...` documented only as a deliberate override. +**Former preservation evidence:** `make help` and package-document checks +verified that the plain native-package targets were the normal path and that +`PACKAGE_VERSION` appeared only as a deliberate override. ### 4. Package Builder Hardening @@ -213,20 +202,20 @@ payload. and now carries a local AppImage target. This fork adds hardening, local identity, and payload consistency constraints. -**Why it matters:** Native packages must install with package-manager-owned +**Why it mattered:** Native packages installed with package-manager-owned system paths, predictable modes, and aligned payloads across formats. -**Current paths:** `scripts/build-deb.sh`, `scripts/build-rpm.sh`, +**Final maintained paths:** `scripts/build-deb.sh`, `scripts/build-rpm.sh`, `scripts/build-pacman.sh`, `scripts/build-appimage.sh`, `scripts/lib/package-common.sh`, `packaging/linux/control`, `packaging/linux/chatgpt.spec`, `packaging/linux/PKGBUILD.template`, `packaging/linux/chatgpt.install`, `packaging/appimage/`, `tests/scripts_smoke.sh`. -**Preservation checks:** Build the affected package format and inspect metadata -plus the first file-listing page. For pacman, check that package ownership is -not inherited from the local build user. For AppImage, check that updater-only -service and polkit files are absent. +**Former preservation evidence:** Reviews built affected package formats and +inspected their metadata and file lists. Pacman packages did not inherit the +local build user's ownership, and AppImage payloads omitted updater-only +service and Polkit files. ### 5. Updater Privilege Boundary And Install Hardening @@ -239,18 +228,18 @@ stage private copies, and then invoke the package manager through `pkexec`. manager and privileged package install path. This fork tightens the boundary and renames the service, policy, and package identities. -**Why it matters:** The updater handles mutable network inputs and local build -work. Privilege must stay isolated to the smallest install surface. +**Why it mattered:** The updater handled mutable network inputs and local build +work. Privilege stayed isolated to the smallest install surface. -**Current paths:** `updater/src/install.rs`, `updater/src/app.rs`, +**Final maintained paths:** `updater/src/install.rs`, `updater/src/app.rs`, `updater/src/config.rs`, `updater/src/builder.rs`, `packaging/linux/com.github.nisavid.chatgpt.update.policy`, `packaging/linux/chatgpt-updater.service`, maintainer scripts, `docs/maintainers/security-backlog.md`, `docs/maintainers/threat-model.md`. -**Preservation checks:** Run updater install tests or targeted review for -state/install changes. Route new trust-boundary work through the security -backlog and `@codex-security` workflow. +**Former preservation evidence:** Updater install tests or targeted review +covered state and install changes. Trust-boundary work was routed through the +security backlog and the `@codex-security` workflow. ### 6. Updater State, Config Overlay, And Failure Recovery @@ -263,16 +252,16 @@ production builder redirection requires `developer_mode = true`. daemon. This fork changes the local names, persisted config surface, recovery rules, and developer-mode guardrails. -**Why it matters:** The updater runs continuously and needs stable persisted +**Why it mattered:** The updater runs continuously and needs stable persisted state across package upgrades, crashes, and user configuration changes. -**Current paths:** `updater/src/app.rs`, `updater/src/config.rs`, +**Final maintained paths:** `updater/src/app.rs`, `updater/src/config.rs`, `updater/src/dmg_source.rs`, `updater/src/builder.rs`, `updater/src/install.rs`, `updater/src/package_version.rs`, `updater/src/codex_cli.rs`, `.github/workflows/updater.yml`, `docs/usage/troubleshooting.md`. -**Preservation checks:** Run full updater tests for state, install, CLI -preflight, liveness, or daemon control-flow changes. +**Former preservation evidence:** Full updater tests covered state, install, +CLI preflight, liveness, and daemon control-flow changes. ### 7. Codex CLI Discovery And Preflight @@ -288,17 +277,18 @@ but preserves `codex` as the invocation name for multicall binaries. preflight. This fork refines discovery precedence, config integration, and best-effort behavior under the `chatgpt-updater` identity. -**Why it matters:** The app needs a reliable Codex CLI path without blocking +**Why it mattered:** The app needs a reliable Codex CLI path without blocking Electron startup on registry or install work that can run later. -**Current paths:** `launcher/start.sh.template`, `install.sh`, +**Final maintained paths:** `launcher/start.sh.template`, `install.sh`, `updater/src/codex_cli.rs`, `updater/src/config.rs`, `updater/src/app.rs`, `updater/src/main.rs`, `updater/src/state.rs`, `docs/usage/troubleshooting.md`, `.github/workflows/updater.yml`. -**Preservation checks:** Keep synchronous path resolution separate from -background npm registry/update checks in docs and tests. Invalid configured -paths should fail loudly; stale persisted paths should not block fallback. +**Former preservation evidence:** Documentation and tests kept synchronous path +resolution separate from background npm registry and update checks. Invalid +configured paths failed loudly, while stale persisted paths did not block +fallback. ### 8. Generated Launcher And Packaged Runtime Behavior @@ -315,18 +305,18 @@ trigger update checks after Electron PID recording. runtime pattern. This fork changes the package-only helper location, service names, environment import policy, and lifecycle details. -**Why it matters:** Package-specific service orchestration must not leak into +**Why it mattered:** Package-specific service orchestration did not leak into checkout builds or race pending updater install state. -**Current paths:** `launcher/start.sh.template`, `install.sh`, +**Final maintained paths:** `launcher/start.sh.template`, `install.sh`, `packaging/linux/chatgpt-packaged-runtime.sh`, `packaging/linux/chatgpt-updater.service`, `packaging/linux/chatgpt-updater-user-service.sh`, `scripts/lib/package-common.sh`, `tests/scripts_smoke.sh`. -**Preservation checks:** Change package-only launcher behavior in -`packaging/linux/chatgpt-packaged-runtime.sh`, then inspect regenerated -`chatgpt/start.sh`. +**Former preservation evidence:** Package-only launcher changes were owned by +`packaging/linux/chatgpt-packaged-runtime.sh` and checked in regenerated +`chatgpt/start.sh` output. ### 9. ASAR, Port Integration, And Linux UI Patch Behavior @@ -350,18 +340,18 @@ material under maintains local patch safety and selected Linux behavior changes on top of that patching system. -**Naming policy:** Durable docs call configurable modules port integrations. -The source path is `port-integrations/`, manifests are `integration.json`, -configs are `integrations.json` or `port-integrations.json`, and environment -variables use `CHATGPT_PORT_INTEGRATIONS_*`. If upstream changes a module under -the old `linux-features/` naming scheme, port the change to the current local -path and preserve the docs terminology. +**Final naming record:** Durable docs called configurable modules port +integrations. The source path was `port-integrations/`, manifests were +`integration.json`, configs were `integrations.json` or +`port-integrations.json`, and environment variables used +`CHATGPT_PORT_INTEGRATIONS_*`. Final syncs reconciled the older +`linux-features/` naming into that local vocabulary. -**Why it matters:** Official app minified bundle shapes change often. Linux -behavior should degrade with actionable warnings instead of breaking app -generation unless a required invariant fails. +**Why it mattered:** Official app minified bundle shapes changed often. Linux +behavior degraded with actionable warnings instead of breaking app generation +unless a required invariant failed. -**Current paths:** `scripts/patch-linux-window-ui.js`, +**Final maintained paths:** `scripts/patch-linux-window-ui.js`, `scripts/patch-linux-window-ui.test.js`, `scripts/lib/asar-patch.sh`, `scripts/lib/port-integrations.js`, `port-integrations/open-target-discovery/`, `port-integrations/remote-control-ui/`, `port-integrations/remote-mobile-control/`, @@ -369,8 +359,8 @@ generation unless a required invariant fails. `launcher/start.sh.template`, `tests/scripts_smoke.sh`, `docs/usage/troubleshooting.md`. -**Preservation checks:** Run the Node patch tests and shell smoke tests when -ASAR patchers or launch flags change. +**Former preservation evidence:** Node patch tests and shell smoke tests +covered ASAR patcher and launch-flag changes. ### 10. Generated-App Mutation Integrity @@ -405,12 +395,12 @@ pipeline and transactional promotion model. This fork adds the central mutation capability, build-only delivery contract, poison propagation, and private candidate lifecycle. -**Why it matters:** Generated official-app files are untrusted build inputs. +**Why it mattered:** Generated official-app files are untrusted build inputs. Capability mediation prevents pathname escape and stale-read replacement from becoming accepted package content, while private candidates preserve the exclusive-writer premise until acceptance. -**Current paths:** `generated-app-mutation-broker/`, +**Final maintained paths:** `generated-app-mutation-broker/`, `scripts/patches/lib/generated-app-mutation-client.js`, `scripts/patches/lib/assets.js`, `scripts/patches/engine.js`, `scripts/patches/runner.js`, `scripts/lib/generated-app-mutation-broker.sh`, @@ -420,15 +410,13 @@ exclusive-writer premise until acceptance. The gate contract is documented in `docs/maintainers/research/generated-app-mutation-integrity-boundary.md`. -**Preservation checks:** Keep the broker out of runtime payloads; bind packaged -prebuilt use to the generated app's exact digest; require the external -broker/app/build-info receipt before native package staging; retain poison/fail-closed -handling and private-root checks. Run `tests/generated_app_mutation_broker.sh` -and `tests/package_release_gate.sh deb`, `tests/package_release_gate.sh rpm`, -and `tests/package_release_gate.sh pacman` for the formats available on the -host. Extracted-app descriptor callbacks, -declarative resource copies, and shell staging hooks remain future Gates 3 and -4; do not describe them as capability-mediated yet. +**Former preservation evidence:** The broker stayed outside runtime payloads; +packaged prebuilt use was bound to the generated app digest; native package +staging required the external broker/app/build-info receipt; and poison, +fail-closed, and private-root checks remained intact. Broker and package-release +tests covered the available native formats. Extracted-app descriptor callbacks, +declarative resource copies, and shell staging hooks remained outside the +capability-mediated claim. ### 11. Webview Server Lifecycle @@ -441,16 +429,16 @@ assets plus `.chatgpt-linux/webview-integrity.sha256` before Electron launch. much of the launcher lifecycle. This fork preserves and renames that behavior while maintaining the local XDG/path contract. -**Why it matters:** ChatGPT expects webview assets at a local origin, while Linux -launches must avoid LAN exposure, stale servers, and PID ownership races. +**Why it mattered:** ChatGPT expected webview assets at a local origin, while +Linux launches avoided LAN exposure, stale servers, and PID ownership races. -**Current paths:** `launcher/start.sh.template`, +**Final maintained paths:** `launcher/start.sh.template`, `launcher/webview-server.py`, `scripts/lib/webview-install.sh`, `install.sh`, `docs/webview-server-evaluation.md`, `docs/usage/troubleshooting.md`, `tests/scripts_smoke.sh`, `tests/webview_probe_equivalence.sh`. -**Preservation checks:** Use `docs/webview-server-evaluation.md` before -changing the local server model, port behavior, or warm-start adoption. +**Former preservation evidence:** Webview server changes were reviewed against +`docs/webview-server-evaluation.md`. ### 12. Linux Computer Use Integration Compatibility @@ -475,25 +463,26 @@ related config write or plugin reconciliation, so stale and late results deny. accessibility tree capture, screenshot paths, and input automation come from upstream in the synced baseline. -**Why it matters:** The package can stage local Computer Use support and register +**Why it mattered:** The package can stage local Computer Use support and register the backend on Linux, but this does not create a grant or server-side entitlement. Codex tool approval, sandboxing, auto-approval, allowed-app selection, and local action validation remain in force. Host accessibility, screenshot, and input readiness can make an authorized action fail; they are not additional grants. -**Current paths:** `computer-use-linux/src/`, +**Final maintained paths:** `computer-use-linux/src/`, `plugins/openai-bundled/plugins/computer-use/`, `scripts/patch-linux-window-ui.js`, `scripts/patch-linux-window-ui.test.js`, `scripts/lib/package-common.sh`, `launcher/start.sh.template`, `README.md`, `docs/usage/build-and-run.md`, `CHANGELOG.md`. -**Preservation checks:** Keep native package staging and README wording scoped to the -local compatibility delta. Preserve the three live authority inputs, fresh -plugin read, generation/token rotation, revoke-before-write/reconcile ordering, -and existing Codex/allowed-app controls. Make clear that local installation does -not bypass OpenAI feature flags. Do not add a fork-owned Computer Use grant, -consent setting, or recurring prompt. +**Former preservation evidence:** Native package staging and README wording +remained scoped to the local compatibility delta. The three live authority +inputs, fresh plugin read, generation and token rotation, +revoke-before-write/reconcile ordering, and existing Codex and allowed-app +controls remained intact. The final implementation did not add a fork-owned +grant, consent setting, or recurring prompt, and did not claim to bypass OpenAI +feature flags. ### 13. Release, Security, And Supply-Chain Verification @@ -519,19 +508,19 @@ host matches `linux-x64-glibc` on `x86_64`, `linux-arm64-glibc` on `aarch64` or `arm64`, or `linux-arm-glibc` on ARMv7 hard-float `armv7l`; unsupported hosts fail before npm or module load. Public native packages require `PACKAGE_WITH_UPDATER=1` and are verified only against the independent immutable -Nix app reference. The release signer must match the exact +Nix app reference. The release signer matched the exact `CHATGPT_RELEASE_GPG_FINGERPRINT`. **Upstream baseline:** Upstream already downloads and converts the official OpenAI ChatGPT DMG. This fork adds extra verification and review gates around that inherited supply chain. -**Why it matters:** This fork rebuilds a package from a mutable official OpenAI -ChatGPT DMG URL. Release and updater work must leave reviewable evidence and -avoid presenting unverified artifacts as trusted. +**Why it mattered:** This fork rebuilt packages from a mutable official OpenAI +ChatGPT DMG URL. Release and updater work left reviewable evidence and avoided +presenting unverified artifacts as trusted. -**Current paths:** `.github/workflows/update-chatgpt-hash.yml`, -`.github/workflows/verify-apple-dmg.yml`, `.github/workflows/ci.yml`, +**Retained source paths:** `.github/workflows/verify-apple-dmg.yml`, +`.github/workflows/ci.yml`, `.github/workflows/updater.yml`, `Makefile`, `flake.nix`, `scripts/release-gate.sh`, `scripts/verify-apple-dmg.sh`, `scripts/inspect-electron-security.js`, `scripts/lib/package-provenance.py`, @@ -540,23 +529,19 @@ avoid presenting unverified artifacts as trusted. `updater/trusted-dmg-manifest.json`, `updater/src/trust.rs`, `updater/src/dmg_source.rs`, `updater/src/app.rs`, `docs/maintainers/security-backlog.md`, `docs/maintainers/threat-model.md`. +The former `.github/workflows/update-chatgpt-hash.yml` write-capable producer +was removed at retirement and remains available only in Git history. + +**Former preservation evidence:** The release surface exposed the Apple DMG +and release gates. Package provenance, public release, updater reproducibility, +Parcel watcher trust, host selection, independent Nix outputs, and the signed +updater-enabled publication path were covered by dedicated tests and builds. +Security backlog work used `@codex-security` before review-ready handoff. -**Preservation checks:** `make help` must show `apple-dmg-verify` and -`release-gate`. Run `tests/package_provenance.sh`, -`tests/package_release_gate.sh` for each available native format, -`tests/release_gate_public_contract.sh`, `tests/updater_reproducibility.sh`, and -`tests/parcel_watcher_trust.sh` when release/package ingress changes. Run -`node --test scripts/lib/parcel-watcher-target.test.js` when host selection -changes. Build -`.#chatgpt-release-app` and `.#release-helpers`, and exercise the public -updater-enabled signed release path, before publication. Security -backlog items that change trust boundaries should use the `@codex-security` -workflow before review-ready handoff. - -The Nix release app must discard the install-time receipt before ELF, mode, and -post-install mutation, then publish a new receipt only after those mutations -finish. Keep the separate flake check that validates the receipt from the final -imported `/nix/store` output. +The Nix release app discarded the install-time receipt before ELF, mode, and +post-install mutation, then published a new receipt only after those mutations +finished. A separate flake check validated the receipt from the final imported +`/nix/store` output. ### 14. User-Local Install Experiment Identity And Layout @@ -569,18 +554,18 @@ layout. This fork renames it and adjusts path choices so it does not reintroduce upstream names or non-XDG roots. -**Why it matters:** The rootless experiment should not reintroduce upstream -names or non-XDG paths while testing a different install model. +**Why it mattered:** The rootless experiment did not reintroduce upstream names +or non-XDG paths while testing a different install model. -**Current paths:** `contrib/user-local-install/README.md`, +**Final maintained paths:** `contrib/user-local-install/README.md`, `contrib/user-local-install/install-user-local.sh`, `contrib/user-local-install/files/.config/systemd/user/`, `contrib/user-local-install/files/.local/bin/`, `contrib/user-local-install/files/.local/share/applications/`, `contrib/user-local-install/files/share/common.sh`. -**Preservation checks:** Keep the payload under -`${XDG_DATA_HOME:-~/.local/share}/chatgpt`; do not use `~/.local/opt`. +**Former preservation evidence:** The user-local payload stayed under the XDG +data directory and did not use `~/.local/opt`. ### 15. Maintainer Policy, Docs, And Agent Workflow @@ -589,25 +574,25 @@ part of upstream: always-loaded agent rules, a repo-local maintenance skill, maintainer references, security backlog, threat model, usage docs, README feature status, and the divergence inventory itself. -**Upstream baseline:** These docs should preserve clear credit for upstream's +**Upstream baseline:** The final docs preserved clear credit for upstream's primary Linux work while describing the local policy and documentation layer as fork finishing work. -**Why it matters:** This fork is intentionally divergent from its upstream. -Future maintainers and agents need durable, discoverable policy without turning +**Why it mattered:** This fork intentionally diverged from its upstream. +Durable, discoverable policy supported maintainers and agents without turning the README or `AGENTS.md` into large maintenance manuals. -**Current paths:** `AGENTS.md`, +**Final maintained paths:** `AGENTS.md`, `.agents/skills/maintaining-chatgpt-package/SKILL.md`, `docs/README.md`, `docs/backlog.md`, `docs/maintainers/package-runtime-maintenance.md`, `docs/maintainers/security-backlog.md`, `docs/maintainers/threat-model.md`, `docs/policies/agentic-maintenance.md`, `docs/usage/`, `README.md`, `CHANGELOG.md`. -**Preservation checks:** Keep `AGENTS.md` short and route details to maintainer -docs or repo-local skills. Check README audience, clone URLs, maintainer-only -material, upstream credit, and divergence accuracy before merging -sync PRs. +**Former preservation evidence:** `AGENTS.md` stayed concise while detailed +contracts lived in maintainer docs or repo-local skills. Sync reviews checked +README audience, clone URLs, maintainer-only material, upstream credit, and +divergence accuracy. ## Layout Triage @@ -617,16 +602,15 @@ Electron-style app bundles. | Surface | Decision | Rationale | | --- | --- | --- | -| Generated native app bundle | Keep `/opt/chatgpt`. | The extracted DMG/Electron tree is a self-contained add-on app bundle. `/opt/` is the conventional location for that shape. | -| User-facing launchers | Keep `/usr/bin/chatgpt` and `/usr/bin/chatgpt-updater`. | Package-managed commands belong on the normal system command path. | -| Update builder bundle | Use `/usr/lib/chatgpt/update-builder`. | The builder is package-private support used by `chatgpt-updater`, not part of the app bundle or user data. | -| Packaged runtime helper | Use `/usr/lib/chatgpt/packaged-runtime.sh`. | The helper is package-private launcher support sourced by the generated launcher only in native package installs. | -| Desktop entry and icon | Keep `/usr/share/applications/chatgpt.desktop` and `/usr/share/icons/hicolor/256x256/apps/chatgpt.png`. | Freedesktop desktop integration is shared, package-managed data. | -| Updater config, state, cache, logs | Keep XDG paths: `~/.config/chatgpt-updater`, `~/.local/state/chatgpt-updater`, `~/.cache/chatgpt-updater`, and `~/.cache/chatgpt/launcher.log`. | These are per-user mutable files and should follow XDG base directories. | -| App PID, webview PID, launch-action socket | Keep `~/.local/state/chatgpt` for persistent state and `$XDG_RUNTIME_DIR/chatgpt` for runtime sockets when available. | Persistent restart state belongs in XDG state; sockets and runtime objects belong in XDG runtime. | -| User-local non-package app payloads | Use `${XDG_DATA_HOME:-~/.local/share}/chatgpt`. Do not use `~/.local/opt`. | XDG has no `~/.local/opt`; user-specific app data should start from the XDG data base directory. | - -No path ambiguity remains for the native package payload after this triage. The -experimental unprivileged install uses XDG user paths and should stay aligned -with this table unless a more specific distro convention is adopted -deliberately. +| Generated native app bundle | Retained `/opt/chatgpt`. | The extracted DMG/Electron tree was a self-contained add-on app bundle. `/opt/` was the conventional location for that shape. | +| User-facing launchers | Retained `/usr/bin/chatgpt` and `/usr/bin/chatgpt-updater`. | Package-managed commands lived on the normal system command path. | +| Update builder bundle | Used `/usr/lib/chatgpt/update-builder`. | The builder was package-private updater support rather than app-bundle or user data. | +| Packaged runtime helper | Used `/usr/lib/chatgpt/packaged-runtime.sh`. | The helper was package-private launcher support sourced only by native package installs. | +| Desktop entry and icon | Retained `/usr/share/applications/chatgpt.desktop` and `/usr/share/icons/hicolor/256x256/apps/chatgpt.png`. | Freedesktop desktop integration was shared, package-managed data. | +| Updater config, state, cache, logs | Retained XDG paths under the user config, state, and cache roots. | These were per-user mutable files governed by XDG base directories. | +| App PID, webview PID, launch-action socket | Retained XDG state for persistent liveness and XDG runtime for sockets. | Persistent restart state and ephemeral runtime objects stayed separate. | +| User-local non-package app payloads | Used `${XDG_DATA_HOME:-~/.local/share}/chatgpt`, not `~/.local/opt`. | XDG supplied the user-specific application data root. | + +No path ambiguity remained for the native package payload after this triage. +The experimental unprivileged install used XDG user paths and stayed aligned +with this table at the final maintained state. diff --git a/docs/maintainers/fork-sync-policy.md b/docs/maintainers/fork-sync-policy.md index f2268e7dc..5ce21b0c5 100644 --- a/docs/maintainers/fork-sync-policy.md +++ b/docs/maintainers/fork-sync-policy.md @@ -1,10 +1,16 @@ # Fork Sync Policy -This is the current procedure for syncing changes from the Linux-port upstream -into this fork. In this document, `upstream` means the `upstream` remote for -`ilysenko/codex-desktop-linux` unless a sentence names another surface. Use this -procedure with [Fork Divergences](fork-divergences.md), the canonical inventory -of local contracts and terminology. +> [!WARNING] +> ChatGPT for Linux is retired and unsupported. This document preserves the +> former sync contract for audit history. Do not use it to start or continue +> maintenance or another sync. See +> [Repository Retirement](../retirement.md). + +This was the procedure for syncing changes from the Linux-port upstream into +this fork. In this historical document, `upstream` means the `upstream` remote +for `ilysenko/codex-desktop-linux` unless a sentence names another surface. The +procedure was used with [Fork Divergences](fork-divergences.md), the canonical +inventory of former local contracts and terminology. The local policy config is `.agents/fork-sync-policy.toml`. It exists for agents and maintainers; runtime code does not consume it. @@ -18,51 +24,52 @@ fields, rename maps, and issue or backlog destinations, then migrate the common behavior into the user-global `syncing-forks-with-upstream` skill. --> -## Required Workflow +## Historical Required Workflow -1. Create a task branch. `main` is protected. -2. Fetch `origin` and `upstream`. -3. Read [Fork Divergences](fork-divergences.md), +Before retirement, a sync used this workflow: + +1. Maintainers created a task branch because `main` was protected. +2. They fetched `origin` and `upstream`. +3. They read [Fork Divergences](fork-divergences.md), `.agents/fork-sync-policy.toml`, and this document before resolving conflicts. -4. Use the user-global `syncing-forks-with-upstream` skill before choosing a +4. They used the user-global `syncing-forks-with-upstream` skill before choosing a merge method or pushing a sync branch. If that external skill is unavailable, - continue from this document and record the missing-skill fallback in the sync - ledger. -5. Preserve upstream commit identity. If a PR is required, merge the sync with a - normal merge commit, not a rebase or squash merge. -6. Preserve this fork's intentional contracts unless the PR intentionally - changes policy. -7. Update the upstream baseline in [Fork Divergences](fork-divergences.md) after - the sync. The policy config points to that canonical inventory instead of - duplicating the mutable commit hash. -8. Compare upstream user-facing docs against this fork's README and usage docs. - Classify relevant additions as adapted under local contracts, already - covered, intentionally omitted, or follow-up. -9. Check [Renamed Path Reconciliation](#renamed-path-reconciliation) before - resolving missing-file, modify/delete, rename/delete, or add/add conflicts. -10. Close any reusable policy gap found during the sync. If the sync reveals a - hazard that future agents could miss, update the narrowest durable policy - surface before handoff. -11. Create or update an in-tree sync ledger entry under + they continued from this document and recorded the missing-skill fallback in + the sync ledger. +5. They preserved upstream commit identity. A required PR merged the sync with + a normal merge commit, not a rebase or squash merge. +6. They preserved this fork's intentional contracts unless the PR intentionally + changed policy. +7. They updated the upstream baseline in + [Fork Divergences](fork-divergences.md) after the sync. The policy config + pointed to that canonical inventory instead of duplicating the mutable + commit hash. +8. They compared upstream user-facing docs against this fork's README and usage + docs, classifying relevant additions as adapted under local contracts, + already covered, intentionally omitted, or follow-up. +9. They checked [Renamed Path Reconciliation](#historical-renamed-path-reconciliation) + before resolving missing-file, modify/delete, rename/delete, or add/add + conflicts. +10. They closed reusable policy gaps found during the sync by updating the + narrowest durable policy surface before handoff. +11. They created or updated an in-tree sync ledger entry under [Fork Sync Ledger](fork-sync-ledger/) before closeout. The PR body may carry a concise summary, but the tracked ledger entry is the durable source. -12. Run the required local gates before the first push that contains code - changes covered by [Local Gates](#local-gates). -13. On the first push of any task branch, create a draft PR in the same - workflow turn. -14. Use `--repo nisavid/chatgpt-linux` on every `gh pr` command in this - checkout. Do not rely on GitHub CLI's inferred repository; it can target the - wrong repository in this fork checkout. -15. Keep the PR in draft until local gates pass and the PR body records - verification evidence. For code-changing branches, the required lifecycle is: - local gates, first push, draft PR, PR verification notes, ready for review. -16. Inspect GitHub blockers directly. Do not infer merge readiness from summary - status alone. - -## Sync Ledger - -Every broad upstream sync needs a tracked ledger entry under +12. They ran the required local gates before the first push containing code + changes covered by [Historical Local Gates](#historical-local-gates). +13. They created a draft PR in the same workflow turn as the first task-branch + push. +14. They used `--repo nisavid/chatgpt-linux` on every `gh pr` command in this + checkout instead of relying on GitHub CLI repository inference. +15. They kept the PR in draft until local gates passed and the PR body recorded + verification evidence. +16. They inspected GitHub blockers directly instead of inferring merge + readiness from summary status alone. + +## Historical Sync Ledger + +Every broad upstream sync required a tracked ledger entry under [Fork Sync Ledger](fork-sync-ledger/) with: - upstream refs fetched and the baseline commit; @@ -89,28 +96,28 @@ Every broad upstream sync needs a tracked ledger entry under - unresolved uncertainties escalated to the operator, or linked to a durable, discoverable follow-up when escalation is unavailable. -Do not push while the ledger has unchecked divergence areas, untriaged -uncertainty, or missing required local gates. +A push remained blocked while the ledger had unchecked divergence areas, +untriaged uncertainty, or missing required local gates. -## Local Gates +## Historical Local Gates -Before pushing changes that affect the generated app, installer, ASAR patcher, -package builders, package payload, updater rebuild flow, or bundled runtime -helpers: +Before retirement, a push affecting the generated app, installer, ASAR +patcher, package builders, package payload, updater rebuild flow, or bundled +runtime helpers required maintainers to: -1. Refresh `ChatGPT.dmg`, or verify the cached DMG was refreshed within the last +1. refresh `ChatGPT.dmg`, or verify the cached DMG was refreshed within the last 24 hours. -2. Run `make build-app` or `./install.sh` from current sources. -3. If package contents changed, run the relevant package builder and inspect +2. run `make build-app` or `./install.sh` from current sources. +3. run the relevant package builder and inspect package metadata plus file listings. -4. If release workflow changed, run the relevant release gate. -5. Record exact commands and results in PR verification notes before marking the +4. run the relevant release gate when release workflow changed. +5. record exact commands and results in PR verification notes before marking the PR ready for review. CI is secondary evidence for these surfaces. It does not replace the local build gate. -## Contract Review +## Historical Contract Review Review incoming changes against every area in [Fork Divergences](fork-divergences.md#divergence-inventory). In particular, @@ -135,7 +142,7 @@ requirements, feature gates, install/update commands, troubleshooting, or validation, but translate names, paths, service identifiers, package filenames, and commands to this fork's local contracts. -## Policy Gap Closeout +## Historical Policy Gap Closeout Treat discovered repeatable sync hazards as part of the sync, not as optional retrospective notes. If a conflict, missed change, review comment, local gate, @@ -160,7 +167,7 @@ follow-up where the escalation would have happened, and keep the safest local guard that prevents dropped upstream changes, history replay, contract drift, or missing verification. -## Renamed Path Reconciliation +## Historical Renamed Path Reconciliation Git's merge strategy normally performs rename detection, but it is similarity based and can still surface an upstream edit as a missing old path, diff --git a/docs/maintainers/package-runtime-maintenance.md b/docs/maintainers/package-runtime-maintenance.md index ffc674564..d39e42a6d 100644 --- a/docs/maintainers/package-runtime-maintenance.md +++ b/docs/maintainers/package-runtime-maintenance.md @@ -1,5 +1,10 @@ # Package and Runtime Maintenance +> [!WARNING] +> This is the historical maintenance contract for the final fork build. Do not +> rebuild, publish, install, update, or restore a producer from these procedures. +> The current boundary is [Repository Retirement](../retirement.md). + This reference is for maintainers changing the Linux packaging, generated launcher, packaged runtime helper, or `chatgpt-updater`. diff --git a/docs/maintainers/security-backlog.md b/docs/maintainers/security-backlog.md index dfe6aca59..fdbb51cfe 100644 --- a/docs/maintainers/security-backlog.md +++ b/docs/maintainers/security-backlog.md @@ -1,31 +1,31 @@ # Security Backlog -Open security follow-up now lives in GitHub Issues. Use this file as the -repository-local index and review workflow pointer. +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [Repository Retirement](../retirement.md). + +This page preserves the former security queue and review workflow. Open items +are unresolved retired risk awaiting truthful tracker disposition, not a work +queue or remediation program. - [All open security backlog issues](https://github.com/nisavid/chatgpt-linux/issues?q=is%3Aissue%20is%3Aopen%20label%3Asecurity%20label%3Abacklog) - [Highest-priority security backlog](https://github.com/nisavid/chatgpt-linux/issues?q=is%3Aissue%20is%3Aopen%20label%3Asecurity%20label%3Abacklog%20label%3A%22priority%2Fhigh%22) - [Medium-priority security backlog](https://github.com/nisavid/chatgpt-linux/issues?q=is%3Aissue%20is%3Aopen%20label%3Asecurity%20label%3Abacklog%20label%3A%22priority%2Fmedium%22) - [Lower-priority security backlog](https://github.com/nisavid/chatgpt-linux/issues?q=is%3Aissue%20is%3Aopen%20label%3Asecurity%20label%3Abacklog%20label%3A%22priority%2Flow%22) -These links use the migrated queue's governed compatibility labels. `security` -marks public security work, `backlog` marks durable follow-up work, and at most -one `priority/*` label records the maintainer's scheduling bucket. The -conjunction of `security` and `backlog` scopes this index to the existing public -security queue. These labels do not replace the repository-wide `type:`, -`area:`, `status:`, or evidence-based `impact:` classification. Scheduling -priority must not be inferred as impact. +These links preserve the migrated queue's historical compatibility labels. +Their priorities record former scheduling decisions, not current work or +security impact. -## Security Review Workflow +## Historical security review workflow -Use the `@codex-security` plugin (`plugin://codex-security@openai-curated`) for -security-sensitive backlog work before implementation is treated as -review-ready. This applies especially to updater trust, privileged install -boundaries, release verification, local rebuild inputs, generated-app IPC, -bundled browser or Chrome native-host behavior, Computer Use desktop control, -and secret redaction. +Before retirement, security-sensitive changes used the `@codex-security` +plugin (`plugin://codex-security@openai-curated`) before implementation was +treated as review-ready. The workflow below is retained only to interpret the +historical review record. -Expected workflow: +The former workflow was: 1. Run the plugin against the current branch and the relevant backlog issue. 2. Record the reviewed trust boundaries, attacker capabilities, and required @@ -37,13 +37,11 @@ Expected workflow: 5. Re-run `@codex-security` or document why the previous result still applies before merging. -`@codex-security` is an additional security review gate. It does not replace -the local build gate, CodeQL, package metadata inspection, threat-model updates, -project [security best practices](security-best-practices.md), or human -maintainer approval where those are required. +`@codex-security` supplemented the local build gate, CodeQL, package metadata +inspection, threat-model updates, project +[security best practices](security-best-practices.md), and human approval. -The filtered links above are authoritative for membership and scheduling -priority. Do not duplicate issue inventories here; completed work otherwise -remains falsely listed as open. The +The filtered links above preserve historical membership and scheduling +priority. The [Remote Mobile Host Boundary Review](remote-mobile-host-boundary-review.md) keeps the repository-local evidence for that specific review surface. diff --git a/docs/maintainers/security-best-practices.md b/docs/maintainers/security-best-practices.md index e51d3d0cf..bec4366ea 100644 --- a/docs/maintainers/security-best-practices.md +++ b/docs/maintainers/security-best-practices.md @@ -1,8 +1,13 @@ # Security Best Practices -This document projects the repository threat model into secure-by-default review -guidance for maintainer changes. Use it with [Threat Model](threat-model.md) -and [Security Backlog](security-backlog.md). +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [Repository Retirement](../retirement.md). + +This document records the secure-by-default review guidance used before +retirement. Read it with [Threat Model](threat-model.md) and +[Security Backlog](security-backlog.md) when interpreting historical work. The current default-enabled port integration set makes generated Electron, webview, and helper-process boundaries the main day-to-day security surface. diff --git a/docs/maintainers/threat-model.md b/docs/maintainers/threat-model.md index faa1e9cad..d2dde6641 100644 --- a/docs/maintainers/threat-model.md +++ b/docs/maintainers/threat-model.md @@ -2,16 +2,15 @@ Date: 2026-07-31 -This repository adapts the official OpenAI `ChatGPT.dmg` into a Linux Electron -app, builds native Linux packages, and ships `chatgpt-updater` to check, -rebuild, and install local updates. This threat model is repository-scoped and -feeds future `@codex-security` reviews. Track actionable implementation work in -[Security Backlog](security-backlog.md). +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [Repository Retirement](../retirement.md). -Use this document to scope security scans and reviews. Use the security backlog -for implementation tickets, and use -[Package and Runtime Maintenance](package-runtime-maintenance.md) for package, -launcher, updater, and validation procedures. +This threat model records the trust boundaries of the former DMG conversion, +native packages, and `chatgpt-updater`. Use it to interpret historical scans +and unresolved retired risk. The [Security Backlog](security-backlog.md) is a +historical inventory, not an implementation queue. ## Executive Summary @@ -1002,9 +1001,9 @@ still contain arbitrary sensitive values. environment, filesystem access. - `packaging/linux/chatgpt-packaged-runtime.sh`: systemd environment import, service startup, launch-time update checks. -- `.github/workflows/update-chatgpt-hash.yml` and - `.github/workflows/verify-apple-dmg.yml`: trust-root update and Apple - verification evidence. +- `.github/workflows/verify-apple-dmg.yml`: retained read-only Apple + verification evidence. The former write-capable + `.github/workflows/update-chatgpt-hash.yml` remains only in Git history. - `flake.nix`: fixed-output DMG hash, Electron patching, Nix-specific runtime behavior. @@ -1019,6 +1018,7 @@ still contain arbitrary sensitive values. public artifacts. - Attacker-controlled inputs are listed separately from findings. - Threats are repository-context classes, not findings about a current diff. -- Current mitigations and gaps match the maintained security backlog. +- The recorded mitigations and gaps match the historical unresolved-risk + inventory. - Maintainer policy remains in maintainer docs; this file is the threat model, - not a replacement for validation instructions or implementation tickets. + not a current validation procedure or implementation queue. diff --git a/docs/policies/agentic-maintenance.md b/docs/policies/agentic-maintenance.md index 1daec249f..928037823 100644 --- a/docs/policies/agentic-maintenance.md +++ b/docs/policies/agentic-maintenance.md @@ -1,8 +1,13 @@ # Agentic Maintenance Policy -This repository is a small package-and-updater project. Leave enough durable -state in tracked files that a future maintainer or agent can continue without -chat history. +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [Repository Retirement](../retirement.md). + +This document records how the former package-and-updater project persisted +maintenance state. The sections below are historical policy, not authority to +resume work. ## What To Persist diff --git a/docs/retirement.md b/docs/retirement.md new file mode 100644 index 000000000..e61fed97f --- /dev/null +++ b/docs/retirement.md @@ -0,0 +1,122 @@ +# Repository Retirement + +ChatGPT for Linux is retired and unsupported. The repository is preserved as a +read-only source, research, and review record while its remaining tracker items +are dispositioned. The GitHub repository will be archived only after that +closeout. Retirement does not turn this community fork into an OpenAI-supported +product, and it does not make the Linux-port upstream responsible for this +fork's local changes. + +## Current user route + +Do not install, rebuild, or update ChatGPT from this repository. Use OpenAI's +official Linux application or a distribution package whose provenance you +independently accept. + +For the CachyOS host evaluated by this project, the selected producer is the +repository-signed `chatgpt-desktop-bin` native repackage. The +[official-app parity record](maintainers/research/official-app-parity-2026-08.md) +documents the accepted provenance, payload comparison, transition, and +essential behavior. This establishes the project's CachyOS decision; it does +not claim vendor support for Arch Linux or CachyOS. + +## Final decision and retained evidence + +The parity and rollback studies were completed before the owner made the final +closeout decision: + +- The + [official-app parity record](maintainers/research/official-app-parity-2026-08.md) + accepted the validated native repackage as the settled producer. +- The + [rollback-evidence retention boundary](maintainers/research/rollback-evidence-retention-boundary-2026-08.md) + identifies which private fallback and recovery artifacts remain useful and + when they can be released. +- The owner subsequently selected retirement and repository archival after the + immediate package-lane withdrawal and tracker closeout. That decision + supersedes older wording that described a maintained fallback or left + retirement contingent on a later evaluation. + +Repository archival does not wait for the delayed rollback tail. The first +ordinary signed package upgrade and post-reboot continuity check remain +downstream milestone +[`arch-pkgs` #76](https://github.com/nisavid/arch-pkgs/issues/76). The later, +target-specific deletion of the retained fallback, recovery snapshot, and +fork-only runtime residue remains +[`arch-pkgs` #77](https://github.com/nisavid/arch-pkgs/issues/77). Those tickets +own M3 and M4 respectively; this repository owns neither the private artifacts +nor their deletion authority. + +## Support and maintenance boundary + +No new builds, releases, dependency refreshes, upstream syncs, DMG refreshes, +package repairs, updater work, compatibility fixes, feature work, or security +fixes are planned here. The source remains available for inspection and +historical reproduction, but its build and install instructions are not a +supported user path. + +New reports should go only to a currently maintained owner after reproducing on +that owner's software: + +- [OpenAI Support](https://help.openai.com/) for the official ChatGPT app or + hosted services; +- [OpenAI's Codex repository](https://github.com/openai/codex) for an inherited + Codex CLI problem; or +- the + [Linux-port upstream](https://github.com/ilysenko/codex-desktop-linux) for a + problem that reproduces in that project and falls within its support policy. + +The `nisavid/chatgpt-linux` tracker is retained for history and closeout, not as +a support queue. + +## Maintenance automation disposition + +Retirement removes every repository automation path that could schedule or +create maintenance work: + +| Producer | Retirement disposition | +| --- | --- | +| Dependabot version updates | `.github/dependabot.yml` is removed. Automated Dependabot security-update pull requests are disabled in repository settings; vulnerability alerts remain visible as historical risk. | +| Private vulnerability reports | Private vulnerability reporting is disabled because the retired repository has no triage or remediation program. Public vulnerability alerts remain enabled as historical risk evidence. | +| Official DMG acceptance | The workflow remains only as read-only pull-request validation. Its hourly schedule, manual dispatch, main-branch trigger, and drift-issue reconciliation job are removed. | +| Nix DMG hash refresh | The write-capable dispatch workflow is removed. The historical refresh scripts remain source evidence, not an active campaign. | +| Cachix population | The cache-writing workflow is removed. Existing cache and workflow-run history are not deleted. | +| CodeQL and Rust Clippy scanning | Required pull-request scanners remain with no schedule, push, or manual trigger. Their only write permission publishes code-scanning results required by protected `main`; existing alerts and run history remain unresolved evidence. | +| Computer Use sync reminder | The issue-writing workflow is removed. Any bounded source export is handled during tracker closeout, without a standing reminder producer. | +| Contributor PR limiting and label management | Pull-request- and issue-mutating workflows are removed because this repository no longer accepts a maintenance queue. | +| Upstream sync | No scheduled upstream-sync workflow was active at retirement. Agent policy now prohibits starting another sync or maintenance campaign without a new owner decision that explicitly reverses retirement. | + +The remaining GitHub Actions workflows have no schedule and no repository, +issue, pull-request, or Actions write permission. CodeQL and Rust Clippy retain +only the `security-events: write` permission needed to publish required +pull-request scan results. Historical workflow definitions and runs remain +available through Git history and the Actions record. + +## Unresolved retired security risk + +Retirement does not remediate or dismiss the repository's open alerts. A live +inventory on 2026-08-18 recorded 10 open Dependabot alerts: + +- high severity: alerts 23 (`undici`) and 33 (`extract-zip`); +- medium severity: alerts 24 through 30 (`undici`) and 32 (`electron`). + +It also recorded high-severity +[CodeQL alert #163](https://github.com/nisavid/chatgpt-linux/security/code-scanning/163), +`actions/cache-poisoning/poisonable-step`. + +These alerts are unresolved retired risk. No assertion is made that the +affected historical source is secure, remediated, or suitable for deployment. +Disabling maintenance producers prevents new automated repair work; it does not +change the alert findings or their severity. + +## Historical documentation + +The remaining architecture, build, package, updater, port-integration, +troubleshooting, DMG, and fork-sync documents describe the final maintained +source state. They are retained to explain the implementation and its evidence, +not as current instructions. The [documentation index](README.md) separates +the retirement record from those historical references. + +The repository remains an unofficial community fork of +[`ilysenko/codex-desktop-linux`](https://github.com/ilysenko/codex-desktop-linux). +It is not affiliated with, endorsed by, sponsored by, or supported by OpenAI. diff --git a/docs/upstream-dmg-acceptance.md b/docs/upstream-dmg-acceptance.md index 678612ecc..b4d7e9729 100644 --- a/docs/upstream-dmg-acceptance.md +++ b/docs/upstream-dmg-acceptance.md @@ -1,11 +1,18 @@ # Official DMG Acceptance -Local installs, updater rebuilds, and the scheduled official-DMG workflow use the -same release profile from `scripts/lib/upstream-dmg-release-profile.js`. Shell -and workflow entrypoints produce reports; `scripts/validate-upstream-dmg.js` -is the only component that decides whether the candidate can be promoted. +> [!WARNING] +> ChatGPT for Linux is retired and unsupported. This acceptance profile is +> preserved as historical release evidence. Do not use it to start or continue +> maintenance, builds, or issue production. See +> [Repository Retirement](retirement.md). -## Verdicts +Before retirement, local installs, updater rebuilds, and the scheduled +official-DMG workflow used the same release profile from +`scripts/lib/upstream-dmg-release-profile.js`. Shell and workflow entrypoints +produced reports; `scripts/validate-upstream-dmg.js` was the only component +that decided whether a candidate could be promoted. + +## Historical Verdicts | Verdict | Meaning | Local promotion | Scheduled issue | |---|---|---:|---:| @@ -14,13 +21,13 @@ is the only component that decides whether the candidate can be promoted. | `rejected` | A required core/integrity check or an enabled port integration drifted | no | create or update the current fingerprint issue | | `inconclusive` | Reports are missing or an infrastructure failure prevented a decision | no | no change | -The profile derives required core patches from patch descriptors and reads the -enabled port integration set from the candidate's patch report. It never enables an -integration for diagnostics. Disabled integrations are not checked; any patch drift in -a user-enabled integration rejects the candidate so the working installation keeps -that integration intact. The user can disable the integration and retry the update. +The profile derived required core patches from patch descriptors and read the +enabled port integration set from the candidate's patch report. It never +enabled an integration for diagnostics. Disabled integrations were not +checked; patch drift in a user-enabled integration rejected the candidate so +the working installation kept that integration intact. -## Transactional Local Install +## Historical Transactional Local Install `install.sh` builds into a hidden sibling candidate directory. It evaluates the candidate patch report and writes @@ -61,26 +68,27 @@ Cleanup keeps the state-referenced DMG and removes older managed hashes plus temporary files abandoned by an interrupted download; unrelated files and symlinks are ignored. -## Drift Issue Lifecycle - -Scheduled runs use the DMG SHA-256 as the identity and the app version only as -a display value. One `area: upstream dmg` issue is kept per rejected fingerprint. -When a new fingerprint arrives, open issues for older DMGs are closed as -superseded. An accepted new DMG closes all remaining drift issues. Before any -mutation, the issue job compares the tested HTTP identity with the current DMG -headers so rerunning an obsolete workflow cannot reopen an old issue. The -identity must contain an ETag or both Last-Modified and Content-Length. If -either the tested or current identity is unavailable, reconciliation makes no -issue changes. The reconciler reads its classification from -`.github/labels.json` and leaves any issue carrying `workflow: manual only` -untouched. -Only issues carrying both the label and a valid hidden 64-character fingerprint -marker are managed. Manually created labeled issues and malformed markers are -never updated, reopened, superseded, or closed by the workflow. - -## Manual Validation - -Normal local builds run acceptance automatically: +## Historical Drift Issue Lifecycle + +Scheduled runs used the DMG SHA-256 as the identity and the app version only as +a display value. One `area: upstream dmg` issue was kept per rejected fingerprint. +When a new fingerprint arrived, open issues for older DMGs were closed as +superseded. An accepted new DMG closed all remaining drift issues. Before any +mutation, the issue job compared the tested HTTP identity with the current DMG +headers so rerunning an obsolete workflow could not reopen an old issue. The +identity had to contain an ETag or both Last-Modified and Content-Length. If +either identity was unavailable, reconciliation made no issue changes. The +reconciler read its classification from `.github/labels.json` and left issues +carrying `workflow: manual only` untouched. Only issues carrying both the label +and a valid hidden 64-character fingerprint marker were managed. Manually +created labeled issues and malformed markers were never updated, reopened, +superseded, or closed by the workflow. + +## Historical Manual Validation + +The commands below are historical evidence and are no longer run for +maintenance or release validation. Before retirement, normal local builds ran +acceptance automatically: ```bash ./install.sh /path/to/ChatGPT.dmg diff --git a/docs/upstream-dmg-intelligence.md b/docs/upstream-dmg-intelligence.md index 309abbdee..16839dcb5 100644 --- a/docs/upstream-dmg-intelligence.md +++ b/docs/upstream-dmg-intelligence.md @@ -1,5 +1,10 @@ # Official OpenAI DMG Intelligence +> [!WARNING] +> Routine DMG inspection is retired. The commands and report format below are +> historical source references, not an active maintenance procedure. See +> [Repository Retirement](retirement.md). + Use this lane when OpenAI ships a new macOS `ChatGPT.dmg` and Linux parity work needs to know what moved before accepting the build. diff --git a/docs/upstream-dmg-watchdog.md b/docs/upstream-dmg-watchdog.md index 596b43742..edc33dbdc 100644 --- a/docs/upstream-dmg-watchdog.md +++ b/docs/upstream-dmg-watchdog.md @@ -1,5 +1,10 @@ # Official DMG watchdog +> [!WARNING] +> The watchdog campaign is retired. Do not install, invoke, requeue, or recreate +> its schedule from this historical procedure. Its write-capable GitHub +> workflow endpoints have been removed. See [Repository Retirement](retirement.md). + The local watchdog turns each official OpenAI ChatGPT DMG SHA-256 into one persistent campaign: ```text diff --git a/docs/usage/build-and-run.md b/docs/usage/build-and-run.md index 94934c6a4..3c9c29c59 100644 --- a/docs/usage/build-and-run.md +++ b/docs/usage/build-and-run.md @@ -1,5 +1,9 @@ # Build and Run Guide +> [!WARNING] +> This is a historical reference for retired, unsupported source. Do not use it +> as a current installation or update path. See [Repository Retirement](../retirement.md). + This guide is for users who want to run ChatGPT on Linux or build a native package from this repository. @@ -148,17 +152,16 @@ Or enter a development shell: nix develop github:nisavid/chatgpt-linux ``` -The flake pins the SRI hash of the official OpenAI `ChatGPT.dmg`. OpenAI -republishes the DMG at the same URL for each release, so the hash can -temporarily lag. A GitHub Actions job refreshes the hash on `main` once every -24 hours. If you see: +The flake pinned the SRI hash of the official OpenAI `ChatGPT.dmg`. OpenAI +republished the DMG at the same URL for each release, so the hash could lag. +The retired project no longer refreshes it. Historical builds can therefore +fail with: ```text error: hash mismatch in fixed-output derivation ``` -retry after the scheduled job has had time to run. If the mismatch remains, -open an issue. +There is no supported repair or issue-reporting path for this repository. ## Generate The Local App diff --git a/docs/usage/support-routing.md b/docs/usage/support-routing.md index a67668f53..c26550e41 100644 --- a/docs/usage/support-routing.md +++ b/docs/usage/support-routing.md @@ -1,82 +1,22 @@ -# Support and Issue Routing - -Use this guide to decide where to report a bug, request a feature, or attribute -behavior in ChatGPT for Linux. - -## What This Project Provides - -This repository does not publish or redistribute the official ChatGPT app. It -provides a recipe that converts the official OpenAI ChatGPT DMG into a local -Linux app, then builds native packages and updater support around that local -build. - -Most user-facing app behavior still comes from the official OpenAI app bundle -and OpenAI-hosted services. OpenAI now publishes an official Linux package, but -does not publish or support this community fork. Behavior introduced by this -fork's DMG conversion, packaging, integrations, or local runtime remains this -project's responsibility. - -## Where To Report - -Report official ChatGPT desktop-app or hosted-service problems through -[OpenAI Support](https://help.openai.com/) when they reproduce in an official -OpenAI build. Report Codex CLI or coding-agent issues to -[OpenAI's Codex repository](https://github.com/openai/codex) only when they -reproduce in the OpenAI-owned Codex interface and are not specific to this -Linux wrapper. - -> [!IMPORTANT] -> When reporting to OpenAI, reproduce in an official macOS or Linux build when -> possible and base the report, screenshots, logs, and terminology on that -> build. Do not report behavior unique to this community fork as an OpenAI app -> bug. - -Report an issue to -[`ilysenko/codex-desktop-linux`](https://github.com/ilysenko/codex-desktop-linux) -when it reproduces in the Linux-port upstream build, or when the change belongs -to the shared Linux conversion layer that this fork inherits. - -> [!IMPORTANT] -> When reporting to the Linux-port upstream, reproduce with a build of -> `ilysenko/codex-desktop-linux` when possible and attach captures or logs from -> that build. Use the Linux-port upstream's names for surfaces that this fork -> renames; see the -> [rename and compatibility map](../maintainers/fork-divergences.md#current-local-rename-and-compatibility-map) -> for the full mapping. - -Report an issue to -[`nisavid/chatgpt-linux`](https://github.com/nisavid/chatgpt-linux) when it -is specific to this fork's package identity, distro-shaped install layout, -updater policy, hardening, supported default integrations, docs, or local -maintenance workflow. Also report here if you cannot reasonably try an -official macOS or Linux build, or the Linux-port upstream reproduction needed -for another tracker. - -If you are unsure, file the issue here and include enough detail to reroute it: -the app version, build method, distro, desktop session, whether the same -behavior reproduces in the Linux-port upstream build, whether it also -reproduces in an official macOS or Linux build, and any reason you could not -attempt those repros. - -## Port Integrations - -Port integrations are build-time integration modules that adapt official ChatGPT app -surfaces or local runtime helpers to this Linux port. The source directory is -`port-integrations/`. - -This fork enables the current supported integration set by default. The default -policy treats these integrations as part of the complete local package, with the -same experimental stability caveats as the rest of the port. Users can disable -an integration when it conflicts with their system or when they want a lighter -build. See [`port-integrations/README.md`](../../port-integrations/README.md) for the -current integration list and config format. - -Port integrations do not bypass OpenAI account policy or service-side rollouts. If -a UI surface depends on OpenAI-hosted account state, MFA, connected-client -state, audio availability, or remote-control enrollment, installing this fork -does not change those requirements. Local control surfaces keep their own -runtime gates: Agent Workspaces uses settings-page approval and permission rules -for the normal UI flow, with main-process bridge hardening tracked in -[#99](https://github.com/nisavid/chatgpt-linux/issues/99); AppShots keeps -global hotkeys inactive until selected; and wrapper update checks stay off until -enabled in Settings. +# Support Routing + +ChatGPT for Linux is retired and unsupported. This repository no longer accepts +bug reports, feature requests, package requests, updater requests, compatibility +work, or security-fix work. See the [retirement record](../retirement.md) for +the current producer and closeout boundary. + +Report a problem elsewhere only after reproducing it on software maintained by +that owner: + +- Use [OpenAI Support](https://help.openai.com/) for the official ChatGPT app or + OpenAI-hosted services. +- Use [OpenAI's Codex repository](https://github.com/openai/codex) for a Codex + CLI or coding-agent problem that reproduces independently of this wrapper. +- Use the + [Linux-port upstream](https://github.com/ilysenko/codex-desktop-linux) for a + Linux-conversion problem that reproduces there and fits that project's own + support policy. + +Do not report behavior unique to this retired community fork as an OpenAI or +Linux-port-upstream bug. Historical issues remain available as evidence; their +continued visibility does not make this tracker a support queue. diff --git a/docs/usage/troubleshooting.md b/docs/usage/troubleshooting.md index eb1b05466..823be7b96 100644 --- a/docs/usage/troubleshooting.md +++ b/docs/usage/troubleshooting.md @@ -1,7 +1,15 @@ # Troubleshooting -This guide lists the fastest checks for common ChatGPT for Linux launch, -package, CLI, and updater problems. +> [!WARNING] +> This page preserves troubleshooting knowledge for retired and unsupported +> source. Do not use this to start or continue maintenance. The commands +> below are historical reference only, not current install, update, +> troubleshooting, or repair instructions. No new support or compatibility +> fixes are provided. See +> [Repository Retirement](../retirement.md). + +Before retirement, this guide listed checks for common ChatGPT for Linux +launch, package, CLI, and updater problems. ## Start With Logs diff --git a/port-integrations/agent-workspace/README.md b/port-integrations/agent-workspace/README.md index 0211b3cb2..cd11c2e74 100644 --- a/port-integrations/agent-workspace/README.md +++ b/port-integrations/agent-workspace/README.md @@ -1,5 +1,10 @@ # Agent Workspaces port integration +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [Repository Retirement](../../docs/retirement.md). + `agent-workspace` is a default-enabled ChatGPT port integration that adds the `agent-workspace-linux` control surface to the app settings UI. diff --git a/port-integrations/x11-ewmh-computer-use/README.md b/port-integrations/x11-ewmh-computer-use/README.md index a67cdb673..6abecdb0b 100644 --- a/port-integrations/x11-ewmh-computer-use/README.md +++ b/port-integrations/x11-ewmh-computer-use/README.md @@ -1,110 +1,21 @@ -# X11/EWMH Computer Use Port Integration - -This optional port integration stages the standalone -`chatgpt-computer-use-x11` MCP plugin into ChatGPT for Linux. It stays disabled -by default. - -## Enable - -For a checkout build, enable it through the git-ignored -`port-integrations/integrations.json` and provide one of the explicit staging -inputs below: - -```json -{ "enabled": ["x11-ewmh-computer-use"] } -``` - -## Baseline - -Supported baseline: Linux Mint Cinnamon on X11 / `x11-ewmh`. - -## Tools exposed - -The staged plugin exposes the standalone namespaced tool surface: - -- `x11_doctor` -- `x11_list_windows` -- `x11_focused_window` -- `x11_focus_window` -- `x11_accessibility_tree` -- `x11_type_text` -- `x11_press_key` -- `x11_click` -- `x11_scroll` -- `x11_drag` -- `x11_get_app_state` -- `x11_target_window` -- `x11_target_context` -- `x11_release_window` - -## Staging modes - -Pinned local artifact mode: - -```bash -export CHATGPT_X11_COMPUTER_USE_RELEASE_TARBALL=/path/to/chatgpt-computer-use-x11-v-x86_64-unknown-linux-gnu.tar.gz -export CHATGPT_X11_COMPUTER_USE_RELEASE_SHA256= -make build-app -``` - -Download mode requires an explicit URL and SHA-256. The integration has no -implicit remote release because the previously pinned repository is no longer -available: - -```bash -export CHATGPT_X11_COMPUTER_USE_DOWNLOAD_URL=https://downloads.example.invalid/chatgpt-computer-use-x11.tar.gz -export CHATGPT_X11_COMPUTER_USE_RELEASE_SHA256= -make build-app -``` - -Set one of the explicit tarball, binary, source, or download inputs before -enabling the integration. Tarball and download modes always require a digest. - -Local source mode: - -```bash -CHATGPT_X11_COMPUTER_USE_SOURCE=/path/to/chatgpt-computer-use-x11 make build-app -``` - -Direct binary test mode: - -```bash -CHATGPT_X11_COMPUTER_USE_BINARY=/path/to/chatgpt-computer-use-x11 make build-app -``` - -## Updater rebuilds - -When this integration is enabled during a native package build that includes -the updater, the package retains the staged executable for updater rebuilds. -Packaging fails if the enabled integration did not stage a regular executable -helper. The updater picker offers the integration only when the installed -builder bundle retains that trusted executable. - -A native package built without this integration cannot newly enable it during -an updater rebuild because it has no package-owned helper to reuse. Build and -install a new native package from a trusted checkout with the integration and -an explicit staging input enabled first. Manually adding the integration to -`${XDG_CONFIG_HOME:-$HOME/.config}/chatgpt/port-integrations.json` does not add -the missing helper. - -For compatibility with older packages, the updater disables a saved X11 -selection in a private build-only config when the installed package does not -retain the helper. The rebuild continues without overwriting the user's saved -preference, so a later package that retains the helper can honor it again. If -the user confirms the picker while the helper is unavailable, the picker -removes the stale selection instead. - -## Backend alignment - -This port integration wires the separate `chatgpt-computer-use-x11` plugin as an opt-in port integration. It does not move X11/EWMH behavior into the core Computer Use backend and does not replace the bundled `computer-use` plugin. - -`agent-sh/computer-use-linux` selectable backend/flavor work is a separate future investigation. If that route proves a better fit, handle it in a separate change or pull request; no backend/flavor experiment may require enabling this port integration by default or modifying core Computer Use behavior in this port integration. - -## Non-goals - -- no core Computer Use replacement; -- no Wayland/RemoteDesktop baseline; -- no default enablement; -- no submodule; -- no global doctor changes; -- no writes to user home from `stage.sh`. +# Historical X11/EWMH Computer Use Port Integration + +> [!IMPORTANT] +> This repository is retired and unsupported. Do not use this to start or +> continue a build, staging, updater, or runtime deployment. See +> [Repository Retirement](../../docs/retirement.md). + +This page is a non-executable historical record of an optional port +integration that was disabled by default. It staged a separate X11/EWMH MCP +backend and did not replace the bundled Computer Use plugin. + +The integration targeted a Linux Mint Cinnamon X11 baseline. Its former tool +surface covered window discovery and focus, accessibility inspection, text and +key input, pointer actions, scrolling and dragging, application state, and +explicit target acquisition and release. + +Historical package builds could retain a package-owned helper for later +rebuilds. Missing or untrusted helper state failed closed, and user preference +state alone could not create the executable. Those boundaries are retained in +Git history for provenance; this retired repository no longer offers an +activation or packaging route. diff --git a/scripts/automation/upstream-dmg-watchdog/SKILL.md b/scripts/automation/upstream-dmg-watchdog/SKILL.md index e7cfcecae..aaacfb48a 100644 --- a/scripts/automation/upstream-dmg-watchdog/SKILL.md +++ b/scripts/automation/upstream-dmg-watchdog/SKILL.md @@ -1,42 +1,20 @@ --- name: upstream-dmg-watchdog -description: Run the versioned official OpenAI ChatGPT DMG probe, repair worker, guarded PR, and sequential Nix refresh flow. +description: Non-executable historical record for the retired and unsupported ChatGPT for Linux repository; do not use it to start or continue maintenance. --- -# Upstream DMG watchdog +# Historical Official DMG Watchdog Skill -Read and follow `docs/upstream-dmg-watchdog.md` and repository `AGENTS.md`. -Use `scripts/automation/upstream-dmg-watchdog/watchdog.py` for every state -transition. Never edit state directly. +> [!IMPORTANT] +> This repository is retired and unsupported. Do not run this skill to start +> or continue probing, worker dispatch, repair, pull-request, or Nix refresh +> work. See [Repository Retirement](../../../docs/retirement.md). -Probe mode runs only: +This file is a non-executable historical record. The former watchdog compared +the mutable official DMG with an accepted identity, coordinated one bounded +worker campaign, recorded acceptance, and reconciled drift issues. -```bash -python3 scripts/automation/upstream-dmg-watchdog/watchdog.py probe -``` - -For `CHANGE_READY SHA EVENT_ID=ID` send `PROCESS_UPSTREAM_DMG SHA` to the -dedicated Worker without model/thinking overrides, then acknowledge `ID`. -For `NIX_REPAIR_READY SHA RUN_ID EVENT_ID=ID` send the complete event to that -same Worker, then acknowledge `ID`. Keep `UNCHANGED`, `WORKER_ACTIVE`, -`NIX_ACTIVE`, and `CAMPAIGN_WAITING` quiet. - -Worker mode follows the complete worker flow in the documentation. In -particular, it must use immutable `sync-integrations`, commit before -`record-acceptance`, pass `nix-preflight`, require all six named repair gates, -call `validate-repair-pr` immediately before merge, and use `advance-to-nix` -instead of `campaign-complete` after an accepted main or confirmed repair merge. - -Classify the changed paths before validation. When every changed path belongs -to the affected `port-integrations//` directories, use the documented -integration-only fast path: run only their Node tests, current-DMG acceptance, and -`nix-preflight --target .#checks.x86_64-linux.nix-port-integrations-multi-integration`. -Open the repair PR after these focused checks and let the six GitHub gates run -in parallel. Do not run `ci-local.sh pr` or local Debian/RPM/pacman builds for a -integration-only drift repair. Use the full local matrix for core, shared loader, -installer, updater, packaging, or mixed-scope changes. - -Use the user's primary checkout as `sync-integrations --source-checkout`, not the -managed repair worktree; this is how its gitignored `integrations.json` and enabled -local integration trees enter the immutable round snapshot. When acceptance reports -an unchanged source head, skip Nix preflight and call `advance-to-nix` directly. +Retirement removed its schedules, write-capable workflows, repair producer, +and package-refresh path. The retained public watchdog program exposes only +read-only status; former mutating modes fail closed. Git history preserves the +last operational protocol and its validation evidence. diff --git a/scripts/automation/upstream-dmg-watchdog/local-skill-adapter.md b/scripts/automation/upstream-dmg-watchdog/local-skill-adapter.md index 0a278b64e..01cce338f 100644 --- a/scripts/automation/upstream-dmg-watchdog/local-skill-adapter.md +++ b/scripts/automation/upstream-dmg-watchdog/local-skill-adapter.md @@ -1,11 +1,15 @@ --- name: upstream-dmg-watchdog -description: Monitor and repair the current official OpenAI ChatGPT DMG through the repository-owned watchdog state machine. +description: Historical watchdog adapter for the retired and unsupported ChatGPT for Linux repository; do not use it to start or continue maintenance. --- -# Upstream DMG watchdog adapter +# Historical upstream DMG watchdog adapter -Resolve the target of `scripts/watchdog.py`, then read the `SKILL.md` beside -that repository-owned implementation completely and follow it. The executable -in this installed skill directory is a symlink to that implementation. Never -maintain a second copy or edit watchdog state directly. +> [!IMPORTANT] +> This is historical source for a retired and unsupported repository. Do not +> use it to start or continue maintenance. Follow +> [`docs/retirement.md`](../../../docs/retirement.md). + +This adapter records how installed watchdog entry points resolved the +repository-owned implementation before retirement. Do not execute or restore +that maintenance path. diff --git a/scripts/automation/upstream-dmg-watchdog/test_watchdog.py b/scripts/automation/upstream-dmg-watchdog/test_watchdog.py index 94b5d3c41..3ef720513 100644 --- a/scripts/automation/upstream-dmg-watchdog/test_watchdog.py +++ b/scripts/automation/upstream-dmg-watchdog/test_watchdog.py @@ -14,6 +14,18 @@ SCRIPT = Path(__file__).with_name("watchdog.py") +HISTORICAL_TEST_DRIVER = """\ +import importlib.util +from pathlib import Path +import sys + +script = Path(sys.argv.pop(1)) +spec = importlib.util.spec_from_file_location("historical_upstream_dmg_watchdog", script) +module = importlib.util.module_from_spec(spec) +sys.modules[spec.name] = module +spec.loader.exec_module(module) +raise SystemExit(module.historical_main()) +""" class WatchdogTests(unittest.TestCase): @@ -111,6 +123,24 @@ def headers(self, name: str, etag: str, source: Path) -> Path: return target def run_cli(self, *args: str, check: bool = True, env: dict | None = None): + return subprocess.run( + [ + "python3", + "-c", + HISTORICAL_TEST_DRIVER, + str(SCRIPT), + *args, + "--state-dir", + str(self.state), + ], + check=check, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env={**os.environ, **(env or {})}, + ) + + def run_public_cli(self, *args: str, check: bool = True, env: dict | None = None): return subprocess.run( ["python3", str(SCRIPT), *args, "--state-dir", str(self.state)], check=check, @@ -120,6 +150,19 @@ def run_cli(self, *args: str, check: bool = True, env: dict | None = None): env={**os.environ, **(env or {})}, ) + def test_retired_public_cli_allows_only_read_only_status(self): + scenario, env = self.write_scenario({}) + + rejected = self.run_public_cli("probe", check=False, env=env) + self.assertEqual(rejected.returncode, 6) + self.assertIn("watchdog is retired", rejected.stderr) + self.assertFalse(scenario.with_suffix(".calls.jsonl").exists()) + self.assertFalse(self.state.exists()) + + status = self.run_public_cli("status") + self.assertEqual(json.loads(status.stdout)["schema"], 2) + self.assertFalse(self.state.exists()) + def probe(self, headers: Path, source: Path, now: float = 1000, check: bool = True): return self.run_cli( "probe", "--headers-file", str(headers), "--source-file", str(source), "--now", str(now), diff --git a/scripts/automation/upstream-dmg-watchdog/watchdog.py b/scripts/automation/upstream-dmg-watchdog/watchdog.py index 59ec4968a..9a632464a 100644 --- a/scripts/automation/upstream-dmg-watchdog/watchdog.py +++ b/scripts/automation/upstream-dmg-watchdog/watchdog.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Atomic local state and cheap upstream DMG probe for ChatGPT for Linux.""" +"""Historical upstream-DMG state reader for retired ChatGPT for Linux.""" from __future__ import annotations @@ -54,6 +54,10 @@ "completed", } STATE_SCHEMA = 2 +RETIRED_EXIT_STATUS = 6 +RETIRED_MESSAGE = ( + "the upstream DMG watchdog is retired; only the read-only status command is available" +) def utc_iso(now: float | None = None) -> str: @@ -2199,8 +2203,7 @@ def command_campaign_complete(args: argparse.Namespace, store: Store) -> int: def command_status(args: argparse.Namespace, store: Store) -> int: - with store.locked(): - print(json.dumps(status_projection(store.load()), indent=2, sort_keys=True)) + print(json.dumps(status_projection(store.load()), indent=2, sort_keys=True)) return 0 @@ -2323,8 +2326,7 @@ def build_parser() -> argparse.ArgumentParser: return parser -def main() -> int: - args = build_parser().parse_args() +def dispatch(args: argparse.Namespace) -> int: store = Store(state_root(args.state_dir)) try: return args.handler(args, store) @@ -2333,5 +2335,18 @@ def main() -> int: return 5 +def historical_main() -> int: + """Exercise the preserved pre-retirement command contract in unit tests.""" + return dispatch(build_parser().parse_args()) + + +def main() -> int: + args = build_parser().parse_args() + if args.command != "status": + print(f"ERROR {RETIRED_MESSAGE}", file=sys.stderr) + return RETIRED_EXIT_STATUS + return dispatch(args) + + if __name__ == "__main__": raise SystemExit(main()) diff --git a/scripts/ci/cachix-workflow.test.js b/scripts/ci/cachix-workflow.test.js index 38f615e15..962e50e65 100644 --- a/scripts/ci/cachix-workflow.test.js +++ b/scripts/ci/cachix-workflow.test.js @@ -5,34 +5,18 @@ const os = require("node:os"); const path = require("node:path"); const test = require("node:test"); -const workflow = fs.readFileSync( - path.resolve(__dirname, "../../.github/workflows/cachix.yml"), - "utf8", -); -const updateHashWorkflow = fs.readFileSync( - path.resolve(__dirname, "../../.github/workflows/update-chatgpt-hash.yml"), - "utf8", -); +const workflowRoot = path.resolve(__dirname, "../../.github/workflows"); const updateHashesScript = path.resolve(__dirname, "update-nix-hashes.sh"); -test("Cachix automatic population runs only for an actual ChatGPT DMG hash change", () => { - assert.match(workflow, /paths:\n\s+- flake\.nix/); - assert.doesNotMatch(workflow, /schedule:/); - assert.match(workflow, /workflow_dispatch:/); - assert.match(workflow, /id: chatgpt-dmg-hash/); - assert.match(workflow, /\.\#checks\.x86_64-linux\.watchdog-port-integrations/); - assert.doesNotMatch(workflow, /watchdog-linux-features/); - assert.match(workflow, /if: github\.event_name != 'workflow_dispatch' \|\| github\.ref == 'refs\/heads\/main'/); - assert.match(workflow, /EVENT_NAME: \$\{\{ github\.event_name \}\}/); - assert.match(workflow, /BEFORE_SHA: \$\{\{ github\.event\.before \}\}/); - assert.match(workflow, /if \[ "\$EVENT_NAME" = "workflow_dispatch" \]; then\n\s+changed=true/); - assert.match(workflow, /read-flake-hash "chatgptDmg = pkgs\.fetchurl \{" "hash = "/); - assert.equal((workflow.match(/read-flake-hash-or-missing/g) ?? []).length, 1); - assert.match(workflow, /FLAKE_FILE="\$previous_flake"[\s\S]*read-flake-hash-or-missing/); - assert.match(workflow, /if: needs\.detect-chatgpt-dmg-hash\.outputs\.changed == 'true'/); +test("Cachix and Nix refresh producer workflows remain retired", () => { + assert.equal(fs.existsSync(path.join(workflowRoot, "cachix.yml")), false); + assert.equal( + fs.existsSync(path.join(workflowRoot, "update-chatgpt-hash.yml")), + false, + ); }); -test("Cachix treats a historical flake without the current DMG anchor as missing", (t) => { +test("historical hash tooling treats a flake without the current DMG anchor as missing", (t) => { const fixtureDir = fs.mkdtempSync(path.join(os.tmpdir(), "chatgpt-cachix-flake-")); t.after(() => fs.rmSync(fixtureDir, { recursive: true, force: true })); const flakePath = path.join(fixtureDir, "flake.nix"); @@ -57,7 +41,7 @@ test("Cachix treats a historical flake without the current DMG anchor as missing assert.equal(result.stdout.trim(), "missing"); }); -test("Cachix rejects a malformed historical block that has the current anchor", (t) => { +test("historical hash tooling rejects a malformed current DMG block", (t) => { const fixtureDir = fs.mkdtempSync(path.join(os.tmpdir(), "chatgpt-cachix-flake-")); t.after(() => fs.rmSync(fixtureDir, { recursive: true, force: true })); const flakePath = path.join(fixtureDir, "flake.nix"); @@ -79,24 +63,3 @@ test("Cachix rejects a malformed historical block that has the current anchor", assert.equal(result.stdout, ""); assert.match(result.stderr, /Could not find 'hash = '/); }); - -test("Nix refresh commits allow post-merge workflows to run", () => { - assert.doesNotMatch(updateHashWorkflow, /\[skip ci\]/); - assert.match(updateHashWorkflow, /gh workflow run ci\.yml/); -}); - -test("Cachix population pushes each output before collecting the Nix store", () => { - assert.match(workflow, /skipPush: true/); - assert.match(workflow, /nix build "\$output"[\s\S]*--print-out-paths/); - assert.doesNotMatch(workflow, /mapfile[^\n]*< <\(/); - assert.match(workflow, /printf '%s\\n' "\$\{store_paths\[@\]\}" \| cachix push "\$CACHIX_CACHE_NAME"/); - assert.match(workflow, /nix store gc/); - assert.ok( - workflow.indexOf("cachix push") < workflow.indexOf("nix store gc"), - "Cachix upload must complete before garbage collection", - ); -}); - -test("Cachix population pins every third-party action", () => { - assert.doesNotMatch(workflow, /uses:\s+[^\s]+@v\d/); -}); diff --git a/scripts/ci/computer-use-sync-reminder.test.js b/scripts/ci/computer-use-sync-reminder.test.js index 582fd0494..5e326b081 100644 --- a/scripts/ci/computer-use-sync-reminder.test.js +++ b/scripts/ci/computer-use-sync-reminder.test.js @@ -1,148 +1,16 @@ -"use strict"; - const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const test = require("node:test"); -const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor; -const repositoryRoot = path.resolve(__dirname, "../.."); -const workflowPath = path.join( - repositoryRoot, - ".github/workflows/computer-use-sync-reminder.yml", -); -const policy = require(path.join(repositoryRoot, ".github/labels.json")); - -function workflowScript() { - const lines = fs.readFileSync(workflowPath, "utf8").split("\n"); - const marker = lines.findIndex((line) => line.trim() === "script: |"); - assert.notEqual(marker, -1, "workflow must contain a github-script block"); - return lines - .slice(marker + 1) - .map((line) => line.replace(/^ {12}/, "")) - .join("\n"); -} - -function harness({ - getLabelError = Object.assign(new Error("missing"), { status: 404 }), - legacyIssue = { number: 944 }, -} = {}) { - const calls = []; - const issues = { - addLabels: async (options) => calls.push(["addLabels", options]), - create: async (options) => calls.push(["create", options]), - createComment: async (options) => calls.push(["createComment", options]), - createLabel: async (options) => calls.push(["createLabel", options]), - getLabel: async (options) => { - calls.push(["getLabel", options]); - if (getLabelError) throw getLabelError; - }, - listForRepo: async (options) => { - calls.push(["listForRepo", options]); - if (options.labels === "computer-use-sync") { - return { data: legacyIssue ? [legacyIssue] : [] }; - } - return { data: [] }; - }, - }; - return { - calls, - core: { notice: (message) => calls.push(["notice", message]) }, - context: { - payload: { compare: "https://github.com/owner/repository/compare/old...new" }, - repo: { owner: "owner", repo: "repository" }, - sha: "0123456789abcdef", - }, - github: { rest: { issues } }, - }; -} - -async function runWorkflow(harnessValue) { - const originalWorkspace = process.env.GITHUB_WORKSPACE; - process.env.GITHUB_WORKSPACE = repositoryRoot; - const requirePolicy = (requestedPath) => { - assert.equal(requestedPath, path.join(repositoryRoot, ".github/labels.json")); - return policy; - }; - try { - const execute = new AsyncFunction("github", "context", "require", "core", workflowScript()); - await execute( - harnessValue.github, - harnessValue.context, - requirePolicy, - harnessValue.core, - ); - } finally { - if (originalWorkspace === undefined) delete process.env.GITHUB_WORKSPACE; - else process.env.GITHUB_WORKSPACE = originalWorkspace; - } -} - -test("sync reminder adopts the legacy open issue during label rollout", async () => { - const value = harness(); - - await runWorkflow(value); - - assert.deepEqual( - value.calls - .filter(([operation]) => operation === "createLabel") - .map(([, options]) => options.name), - ["type: maintenance", "area: computer use", "status: ready for work", "sync: computer use"], +test("Computer Use issue-producing sync reminder remains retired", () => { + assert.equal( + fs.existsSync( + path.resolve( + __dirname, + "../../.github/workflows/computer-use-sync-reminder.yml", + ), + ), + false, ); - const addLabels = value.calls.find(([operation]) => operation === "addLabels"); - assert.deepEqual(addLabels[1], { - owner: "owner", - repo: "repository", - issue_number: 944, - labels: [ - "type: maintenance", - "area: computer use", - "status: ready for work", - "sync: computer use", - ], - }); - const comment = value.calls.find(([operation]) => operation === "createComment"); - assert.equal(comment[1].issue_number, 944); - assert.equal(value.calls.some(([operation]) => operation === "create"), false); -}); - -test("sync reminder creates new issues with a complete governed classification", async () => { - const value = harness({ legacyIssue: null }); - - await runWorkflow(value); - - assert.deepEqual(value.calls.find(([operation]) => operation === "create")[1].labels, [ - "type: maintenance", - "area: computer use", - "status: ready for work", - "sync: computer use", - ]); -}); - -test("sync reminder fails closed when label lookup fails for a non-404 reason", async () => { - const value = harness({ getLabelError: Object.assign(new Error("forbidden"), { status: 403 }) }); - - await assert.rejects(() => runWorkflow(value), /forbidden/); - - assert.equal(value.calls.some(([operation]) => operation === "createLabel"), false); - assert.equal(value.calls.some(([operation]) => operation === "create"), false); -}); - -test("sync reminder preserves a manual-only item without commenting", async () => { - const value = harness({ - legacyIssue: { number: 944, labels: [{ name: "workflow: manual only" }] }, - }); - - await runWorkflow(value); - - assert.equal(value.calls.some(([operation]) => operation === "addLabels"), false); - assert.equal(value.calls.some(([operation]) => operation === "createComment"), false); - assert.equal(value.calls.some(([operation]) => operation === "create"), false); -}); - -test("sync reminder workflow serializes runs and pins third-party actions", () => { - const workflow = fs.readFileSync(workflowPath, "utf8"); - assert.match(workflow, /group: computer-use-sync-reminder/); - assert.match(workflow, /cancel-in-progress: false/); - assert.doesNotMatch(workflow, /uses:\s+[^\s]+@v\d/); }); diff --git a/scripts/ci/enforce-pr-limit.test.js b/scripts/ci/enforce-pr-limit.test.js index d8d07f2c5..5fade5355 100644 --- a/scripts/ci/enforce-pr-limit.test.js +++ b/scripts/ci/enforce-pr-limit.test.js @@ -452,37 +452,11 @@ test("enforcePullRequestLimits retries closing before failing", async () => { assert.equal(harness.messages.warning.length, 3); }); -test("workflow uses the trusted pull_request_target configuration", () => { - const workflow = fs.readFileSync( - path.resolve(__dirname, "../../.github/workflows/contributor-pr-limit.yml"), - "utf8", - ); - - assert.match(workflow, /pull_request_target:\n\s+types: \[opened, reopened\]/); - assert.match(workflow, /contents: read\n\s+pull-requests: write/); - assert.doesNotMatch(workflow, /issues: write/); - assert.doesNotMatch(workflow, /pr-limit-pending|addLabels|queue-event/); - assert.match( - workflow, - /group: contributor-pr-limit\n\s+cancel-in-progress: false/, - ); - assert.match(workflow, /ref: \$\{\{ github\.event\.repository\.default_branch \}\}/); - assert.match(workflow, /persist-credentials: false/); - assert.match( - workflow, - /actions\/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7\.0\.0/, - ); - assert.match( - workflow, - /actions\/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9\.0\.0/, - ); - assert.match( - workflow, - /MAX_OPEN_PRS_PER_CONTRIBUTOR: \$\{\{ vars\.MAX_OPEN_PRS_PER_CONTRIBUTOR \}\}/, - ); - assert.match( - workflow, - /MAX_OPEN_PRS_PER_CONTRIBUTOR_OVERRIDES: \$\{\{ vars\.MAX_OPEN_PRS_PER_CONTRIBUTOR_OVERRIDES \}\}/, +test("contributor pull-request mutation workflow remains retired", () => { + assert.equal( + fs.existsSync( + path.resolve(__dirname, "../../.github/workflows/contributor-pr-limit.yml"), + ), + false, ); - assert.doesNotMatch(workflow, /github\.event\.pull_request\.head/); }); diff --git a/scripts/ci/manage-labels.test.js b/scripts/ci/manage-labels.test.js index f2a8fa95c..8d8d4ce98 100644 --- a/scripts/ci/manage-labels.test.js +++ b/scripts/ci/manage-labels.test.js @@ -409,29 +409,11 @@ test("writeSnapshot uses private permissions and never overwrites an audit snaps } }); -test("label management workflow keeps writes manual, trusted, and snapshotted", async () => { - const workflow = await fs.readFile( - path.resolve(__dirname, "../../.github/workflows/manage-labels.yml"), - "utf8", +test("label management workflow remains retired", async () => { + await assert.rejects( + fs.access(path.resolve(__dirname, "../../.github/workflows/manage-labels.yml")), + (error) => error?.code === "ENOENT", ); - assert.match(workflow, /workflow_dispatch:/); - assert.match(workflow, /Plan triage and catalog changes/); - assert.doesNotMatch(workflow, /pull_request(?:_target)?:/); - assert.match(workflow, /^permissions: \{\}$/m); - assert.equal( - (workflow.match(/ref: \$\{\{ github\.event\.repository\.default_branch \}\}/g) || []).length, - 2, - ); - assert.match(workflow, /issues: read\n\s+pull-requests: read/); - assert.match(workflow, /issues: write\n\s+pull-requests: write/); - assert.match(workflow, /apply:APPLY\|retire:RETIRE/); - assert.doesNotMatch(workflow, /uses:\s+[^\s]+@v\d/); - - const snapshot = workflow.indexOf("Capture the pre-change audit snapshot"); - const artifact = workflow.indexOf("Preserve the pre-change audit snapshot"); - const apply = workflow.indexOf("Converge desired labels and migrate associations"); - const retire = workflow.indexOf("Retire obsolete labels"); - assert.ok(snapshot > 0 && snapshot < artifact && artifact < apply && apply < retire); }); test("buildRestorePlan restores only explicitly retired labels and their saved associations", () => { diff --git a/scripts/ci/retirement-posture.test.js b/scripts/ci/retirement-posture.test.js new file mode 100644 index 000000000..a02b4e3fa --- /dev/null +++ b/scripts/ci/retirement-posture.test.js @@ -0,0 +1,571 @@ +const assert = require("node:assert/strict"); +const childProcess = require("node:child_process"); +const crypto = require("node:crypto"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const test = require("node:test"); + +const repoRoot = path.resolve(__dirname, "../.."); +const workflowRoot = path.join(repoRoot, ".github/workflows"); + +const retiredWorkflowFiles = [ + "cachix.yml", + "computer-use-sync-reminder.yml", + "contributor-pr-limit.yml", + "manage-labels.yml", + "update-chatgpt-hash.yml", +]; + +const requiredPullRequestScannerFiles = ["codeql.yml", "rust-clippy.yml"]; +const historicalExecutableFencePattern = /(?:`{3,}|~{3,})/; + +// actionlint validates syntax; exact digests freeze the reviewed +// retirement-only semantics. +const retainedWorkflowDigests = new Map([ + [ + "ci.yml", + "d9c3973e495b687afd57eee948944ad4744f047e8524c6d967bf19075312f11f", + ], + [ + "codeql.yml", + "94cae7fb4319d32a2ae265c7afd276c7727c493416c7584756e6a3d74fd31bc5", + ], + [ + "install-deps.yml", + "caba37cc040b444099a358ef262461ff17ecce37750727634d86115faae633a4", + ], + [ + "official-dmg-build-app.yml", + "9868109e49926bfe830b944af45c4b6b4c2851ba69cc647a6c201258b6e2915b", + ], + [ + "rust-clippy.yml", + "fc045e04723fde9a3a2e79f0958cfdcad029ce450c0e728fd671352eba2db4c7", + ], + [ + "updater.yml", + "e20b022b64b09a8675425e4e3a95a4cfa333d1848470f81536b5eeb362aaad16", + ], + [ + "verify-apple-dmg.yml", + "009a063b868bffa2e52a539b91221e3353c7abaf57991cd44f72108e163ce01c", + ], +]); + +function sha256(bytes) { + return crypto.createHash("sha256").update(bytes).digest("hex"); +} + +function assertRetainedWorkflowDigest(workflow, bytes) { + const expected = retainedWorkflowDigests.get(workflow); + assert.ok(expected, `${workflow} has no frozen retirement workflow digest`); + assert.equal( + sha256(bytes), + expected, + `${workflow} changed after retirement; ` + + "if this edit is authorized, review and update retainedWorkflowDigests", + ); +} + +function assertRetainedWorkflowFile(workflow, workflowPath) { + assert.equal( + fs.lstatSync(workflowPath).isFile(), + true, + `${workflow} must remain a regular file`, + ); + assertRetainedWorkflowDigest(workflow, fs.readFileSync(workflowPath)); +} + +function assertRetainedWorkflowDirectories(repositoryRoot) { + for (const relativePath of [".github", ".github/workflows"]) { + assert.equal( + fs.lstatSync(path.join(repositoryRoot, relativePath)).isDirectory(), + true, + `${relativePath} must remain a real directory`, + ); + } +} + +const historicalAgentEntryPoints = [ + "DESIGN.md", + "PRODUCT.md", + ".agents/skills/maintaining-chatgpt-package/SKILL.md", + "docs/agents/domain.md", + "docs/agents/generated-and-runtime-notes.md", + "docs/agents/repository-map.md", + "docs/agents/validation-playbook.md", + "docs/github-cli-auth.md", + "docs/label-governance.md", + "docs/maintainers/security-best-practices.md", + "docs/maintainers/security-backlog.md", + "docs/maintainers/fork-sync-policy.md", + "docs/maintainers/threat-model.md", + "docs/policies/agentic-maintenance.md", + "docs/upstream-dmg-acceptance.md", + "docs/usage/troubleshooting.md", + "port-integrations/agent-workspace/README.md", + "port-integrations/x11-ewmh-computer-use/README.md", + "scripts/automation/upstream-dmg-watchdog/SKILL.md", + "scripts/automation/upstream-dmg-watchdog/local-skill-adapter.md", +]; + +const nonExecutableHistoricalEntryPoints = new Map([ + [ + ".agents/skills/maintaining-chatgpt-package/SKILL.md", + [ + /^## Start Discovery$/m, + /^## Native Package Shape$/m, + /^## Verification$/m, + /make build-app/, + /\.\/install\.sh/, + /Before pushing/i, + /For native package changes/i, + /supported successor/i, + /distributed locally as `chatgpt-desktop-bin`/i, + ], + ], + [ + "port-integrations/x11-ewmh-computer-use/README.md", + [ + /^## Enable$/m, + /^## Staging modes$/m, + /^## Updater rebuilds$/m, + /CHATGPT_X11_COMPUTER_USE_/, + /make build-app/, + /integrations\.json/, + ], + ], + [ + "scripts/automation/upstream-dmg-watchdog/SKILL.md", + [ + /watchdog\.py\s+(?:probe|worker)/, + /PROCESS_UPSTREAM_DMG/, + /record-acceptance/, + /nix-preflight/, + /Open the repair PR/i, + ], + ], + [ + "docs/agents/domain.md", + [ + /Before exploring/i, + /Use the glossary vocabulary/i, + /Flag ADR conflicts/i, + /before doing ordinary work/i, + /Use the specific term/i, + ], + ], + [ + "PRODUCT.md", + [ + /ChatGPT for Linux serves/i, + /Success means/i, + /Future work should/i, + /The product should/i, + /should target WCAG/i, + /surfaces were[^.]*privacy-safe/i, + /They did not fabricate/i, + ], + ], + [ + "docs/agents/generated-and-runtime-notes.md", + [ + /Override only/i, + /should be idempotent/i, + /Do not fix/i, + /before changing/i, + /For current navigation/i, + ], + ], + [ + "docs/agents/repository-map.md", + [ + /Edit this/i, + /Current Route/i, + /Start here when/i, + /Use `port-integrations\//i, + /Read it before/i, + /Add new compositor/i, + ], + ], +]); + +test("retained retirement workflows match the exact reviewed bytes", () => { + assertRetainedWorkflowDirectories(repoRoot); + const workflows = fs + .readdirSync(workflowRoot) + .filter((name) => /\.ya?ml$/.test(name)) + .sort(); + + assert.deepEqual(workflows, [...retainedWorkflowDigests.keys()].sort()); + for (const workflow of workflows) { + assertRetainedWorkflowFile(workflow, path.join(workflowRoot, workflow)); + } + + const ciSource = fs.readFileSync(path.join(workflowRoot, "ci.yml"), "utf8"); + for (const mutation of [ + ciSource.replace(" pull_request:", " pull_request_target:"), + ciSource.replace(" contents: read", " contents: write"), + `${ciSource}\n# changed after retirement\n`, + ]) { + assert.notEqual(mutation, ciSource); + assert.throws( + () => assertRetainedWorkflowDigest("ci.yml", Buffer.from(mutation)), + /changed after retirement;.*retainedWorkflowDigests/, + ); + } + + const fixtureRoot = fs.mkdtempSync( + path.join(os.tmpdir(), "chatgpt-retired-workflow-"), + ); + try { + const target = path.join(fixtureRoot, "target.yml"); + const link = path.join(fixtureRoot, "ci.yml"); + fs.writeFileSync(target, ciSource); + fs.symlinkSync(target, link); + assert.throws( + () => assertRetainedWorkflowFile("ci.yml", link), + /regular file/, + ); + + const linkedRepo = path.join(fixtureRoot, "linked-repo"); + fs.mkdirSync(linkedRepo); + fs.symlinkSync( + path.join(repoRoot, ".github"), + path.join(linkedRepo, ".github"), + "dir", + ); + assert.throws( + () => assertRetainedWorkflowDirectories(linkedRepo), + /real directory/, + ); + + const linkedWorkflowsRepo = path.join(fixtureRoot, "linked-workflows-repo"); + fs.mkdirSync(path.join(linkedWorkflowsRepo, ".github"), { + recursive: true, + }); + fs.symlinkSync( + workflowRoot, + path.join(linkedWorkflowsRepo, ".github/workflows"), + "dir", + ); + assert.throws( + () => assertRetainedWorkflowDirectories(linkedWorkflowsRepo), + /real directory/, + ); + } finally { + fs.rmSync(fixtureRoot, { recursive: true, force: true }); + } +}); + +test("retirement posture replaces install and support entry points", () => { + const readme = fs.readFileSync(path.join(repoRoot, "README.md"), "utf8"); + const contributing = fs.readFileSync( + path.join(repoRoot, "CONTRIBUTING.md"), + "utf8", + ); + const security = fs.readFileSync(path.join(repoRoot, "SECURITY.md"), "utf8"); + const pullRequestTemplate = fs.readFileSync( + path.join(repoRoot, ".github/pull_request_template.md"), + "utf8", + ); + const pullRequestTemplateProse = pullRequestTemplate.replace(/^>\s?/gm, ""); + const backlog = fs.readFileSync(path.join(repoRoot, "docs/backlog.md"), "utf8"); + const issueTracker = fs.readFileSync( + path.join(repoRoot, "docs/agents/issue-tracker.md"), + "utf8", + ); + const retirement = fs.readFileSync( + path.join(repoRoot, "docs/retirement.md"), + "utf8", + ); + + assert.match(readme, /retired and unsupported/i); + assert.match(readme, /chatgpt-desktop-bin/); + assert.match(readme, /ilysenko\/codex-desktop-linux/); + assert.match(readme, /unofficial community project/i); + assert.doesNotMatch(readme, /^## Quick Start$/m); + assert.doesNotMatch(readme, /^## Local Updater$/m); + + assert.match(contributing, /retired and unsupported/i); + assert.match(contributing, /not accepting\s+contributions/i); + assert.doesNotMatch(contributing, /Contributions of all sizes are welcome/i); + assert.doesNotMatch(contributing, /^## Development Setup$/m); + + assert.match(security, /retired and unsupported/i); + assert.match(security, /does not accept vulnerability reports/i); + assert.doesNotMatch(security, /^## Supported Versions$/m); + assert.doesNotMatch(security, /maintainers coordinate the fix/i); + + assert.match(pullRequestTemplate, /owner-directed retirement closeout/i); + assert.match(pullRequestTemplate, /^# Pull Request Closeout$/m); + assert.match( + pullRequestTemplateProse, + /does not accept\s+maintenance contributions/i, + ); + assert.doesNotMatch(pullRequestTemplate, /automated bot will close/i); + assert.doesNotMatch(pullRequestTemplate, /latest `ChatGPT\.dmg`/i); + + assert.match(backlog, /closed to new work/i); + assert.doesNotMatch(backlog, /Keep new durable work items/i); + assert.doesNotMatch(backlog, /active queue/i); + + assert.match(issueTracker, /retirement closeout/i); + assert.doesNotMatch(issueTracker, /gh issue create/); + assert.doesNotMatch(issueTracker, /Create a GitHub issue/i); + + assert.match( + security, + /https:\/\/openai\.com\/security\/disclosure/, + ); + + assert.match(retirement, /official-app-parity-2026-08\.md/); + assert.match(retirement, /rollback-evidence-retention-boundary-2026-08\.md/); + assert.match(retirement, /arch-pkgs\/issues\/76/); + assert.match(retirement, /arch-pkgs\/issues\/77/); + assert.match(retirement, /10 open Dependabot alerts/); + assert.match(retirement, /CodeQL alert #163/); + assert.match( + retirement, + /https:\/\/github\.com\/nisavid\/chatgpt-linux\/security\/code-scanning\/163/, + ); + assert.doesNotMatch(retirement, /(?:^|\s)#(?:23|33|2[4-9]|30|32)\b/m); + assert.match(retirement, /unresolved retired risk/i); + assert.match(retirement, /will be archived only after that\s+closeout/i); + assert.doesNotMatch(retirement, /repository is archived/i); +}); + +test("direct agent and security entry points fail closed into retirement", () => { + for (const relativePath of historicalAgentEntryPoints) { + const source = fs.readFileSync(path.join(repoRoot, relativePath), "utf8"); + const prose = source.replace(/^>\s?/gm, ""); + assert.match(prose, /retired and unsupported/i, relativePath); + assert.match(prose, /retirement\.md/, relativePath); + assert.match( + prose, + /do not\s+(?:use (?:it|this)|run it) to (?:start|continue)/i, + relativePath, + ); + } + + const labelGovernance = fs.readFileSync( + path.join(repoRoot, "docs/label-governance.md"), + "utf8", + ); + assert.doesNotMatch(labelGovernance, /\.github\/workflows\/manage-labels\.yml/); + assert.doesNotMatch(labelGovernance, /GITHUB_TOKEN=.*manage-labels\.js/); + assert.doesNotMatch(labelGovernance, /trusted manual workflow/i); + assert.doesNotMatch(labelGovernance, /repository-owned issue producers must/i); + assert.match(labelGovernance, /former manual label workflow/i); + assert.match(labelGovernance, /not an authorized mutation path/i); + + const forkDivergences = fs.readFileSync( + path.join(repoRoot, "docs/maintainers/fork-divergences.md"), + "utf8", + ); + assert.doesNotMatch( + forkDivergences, + /\*\*Current paths:\*\*[^\n]*update-chatgpt-hash\.yml/, + ); + assert.match(forkDivergences, /removed at retirement/i); + + const threatModel = fs.readFileSync( + path.join(repoRoot, "docs/maintainers/threat-model.md"), + "utf8", + ); + assert.doesNotMatch(threatModel, /maintained security backlog/i); + assert.doesNotMatch(threatModel, /implementation tickets/i); + assert.match(threatModel, /former write-capable/i); + + const forkSyncPolicy = fs.readFileSync( + path.join(repoRoot, "docs/maintainers/fork-sync-policy.md"), + "utf8", + ); + assert.match(forkSyncPolicy, /^## Historical Required Workflow$/m); + assert.match(forkSyncPolicy, /^## Historical Sync Ledger$/m); + assert.doesNotMatch(forkSyncPolicy, /^## Required Workflow$/m); + + const dmgAcceptance = fs.readFileSync( + path.join(repoRoot, "docs/upstream-dmg-acceptance.md"), + "utf8", + ); + assert.match(dmgAcceptance, /^## Historical Drift Issue Lifecycle$/m); + assert.match(dmgAcceptance, /^## Historical Manual Validation$/m); + assert.doesNotMatch(dmgAcceptance, /^## Manual Validation$/m); + + const troubleshooting = fs.readFileSync( + path.join(repoRoot, "docs/usage/troubleshooting.md"), + "utf8", + ); + const troubleshootingProse = troubleshooting.replace(/^>\s?/gm, ""); + assert.match( + troubleshootingProse, + /commands\s+below are historical reference only/i, + ); +}); + +test("historical entry points reject every CommonMark fence form", () => { + for (const fence of [ + " ```sh", + "~~~sh", + " ~~~~", + "> ```console", + " > > ~~~sh", + "- ```sh", + "1. ~~~console", + "> - ```sh", + ]) { + assert.equal( + historicalExecutableFencePattern.test(fence), + true, + `fence must be rejected: ${fence}`, + ); + } +}); + +test("historical maintenance entry points contain no executable work route", () => { + for (const [relativePath, forbiddenPatterns] of + nonExecutableHistoricalEntryPoints) { + const source = fs.readFileSync(path.join(repoRoot, relativePath), "utf8"); + const prose = source.replace(/^>\s?/gm, ""); + assert.match(prose, /non-executable historical (?:record|context)/i, relativePath); + assert.doesNotMatch(source, historicalExecutableFencePattern, relativePath); + for (const forbiddenPattern of forbiddenPatterns) { + assert.doesNotMatch(source, forbiddenPattern, relativePath); + } + } + + const forkDivergences = fs.readFileSync( + path.join(repoRoot, "docs/maintainers/fork-divergences.md"), + "utf8", + ); + assert.match(forkDivergences, /non-executable historical record/i); + assert.doesNotMatch( + forkDivergences, + /Use this inventory during upstream syncs/i, + ); + assert.doesNotMatch(forkDivergences, /^## Sync Review Rule$/m); + assert.doesNotMatch(forkDivergences, /^\*\*Preservation checks:\*\*/m); + + const securityBacklog = fs.readFileSync( + path.join(repoRoot, "docs/maintainers/security-backlog.md"), + "utf8", + ); + assert.match( + securityBacklog, + /not a work\s+queue or remediation program/i, + ); + assert.match(securityBacklog, /Historical security review workflow/i); + assert.doesNotMatch(securityBacklog, /current remediation workflow/i); +}); + +test("retired watchdog public CLI exposes status but rejects mutation", () => { + const fixtureRoot = fs.mkdtempSync( + path.join(os.tmpdir(), "chatgpt-retired-watchdog-"), + ); + const binDir = path.join(fixtureRoot, "bin"); + const stateDir = path.join(fixtureRoot, "state"); + const ghMarker = path.join(fixtureRoot, "gh-called"); + const watchdog = path.join( + repoRoot, + "scripts/automation/upstream-dmg-watchdog/watchdog.py", + ); + fs.mkdirSync(binDir); + const fakeGh = path.join(binDir, "gh"); + fs.writeFileSync( + fakeGh, + '#!/bin/sh\n: > "$WATCHDOG_GH_MARKER"\nexit 99\n', + { mode: 0o755 }, + ); + const env = { + ...process.env, + PATH: `${binDir}:${process.env.PATH || ""}`, + WATCHDOG_GH_MARKER: ghMarker, + }; + + try { + const rejected = childProcess.spawnSync( + "python3", + [watchdog, "probe", "--state-dir", stateDir], + { encoding: "utf8", env }, + ); + assert.equal(rejected.status, 6, rejected.stderr); + assert.match(rejected.stderr, /watchdog is retired/i); + assert.equal(fs.existsSync(ghMarker), false); + assert.equal(fs.existsSync(stateDir), false); + + const status = childProcess.spawnSync( + "python3", + [watchdog, "status", "--state-dir", stateDir], + { encoding: "utf8", env }, + ); + assert.equal(status.status, 0, status.stderr); + assert.equal(JSON.parse(status.stdout).schema, 2); + assert.equal(fs.existsSync(ghMarker), false); + assert.equal(fs.existsSync(stateDir), false); + } finally { + fs.rmSync(fixtureRoot, { recursive: true, force: true }); + } +}); + +test("retirement posture disables dependency and maintenance producers", () => { + assert.equal( + fs.existsSync(path.join(repoRoot, ".github/dependabot.yml")), + false, + ); + + for (const workflow of retiredWorkflowFiles) { + assert.equal( + fs.existsSync(path.join(workflowRoot, workflow)), + false, + `${workflow} must remain retired`, + ); + } + + for (const workflow of requiredPullRequestScannerFiles) { + const source = fs.readFileSync(path.join(workflowRoot, workflow), "utf8"); + assert.match(source, /^\s*pull_request:\s*$/m, workflow); + assert.doesNotMatch( + source, + /^\s*(push|schedule|workflow_dispatch):/m, + workflow, + ); + assert.match(source, /^\s*security-events:\s*write\s*$/m, workflow); + } +}); + +test("remaining workflows cannot schedule or mutate repository maintenance state", () => { + const workflows = fs + .readdirSync(workflowRoot) + .filter((name) => /\.ya?ml$/.test(name)) + .sort(); + + for (const workflow of workflows) { + const source = fs.readFileSync(path.join(workflowRoot, workflow), "utf8"); + assert.doesNotMatch(source, /^\s*schedule:\s*$/m, workflow); + } + + const officialDmg = fs.readFileSync( + path.join(workflowRoot, "official-dmg-build-app.yml"), + "utf8", + ); + assert.match(officialDmg, /^\s*pull_request:\s*$/m); + assert.doesNotMatch(officialDmg, /^\s*(push|schedule|workflow_dispatch):/m); + assert.doesNotMatch(officialDmg, /reconcile-official-dmg-issue/); + assert.doesNotMatch(officialDmg, /reconcileUpstreamDmgIssue/); + + const ci = fs.readFileSync(path.join(workflowRoot, "ci.yml"), "utf8"); + assert.doesNotMatch(ci, /scheduled hash-refresh workflow/i); + assert.doesNotMatch(ci, /hash-refresh workflow owns/i); + assert.doesNotMatch(ci, /migration in issue #123/i); + assert.match(ci, /historical external cache/i); + assert.match(ci, /no maintenance producer/i); + + const appleDmg = fs.readFileSync( + path.join(workflowRoot, "verify-apple-dmg.yml"), + "utf8", + ); + assert.doesNotMatch(appleDmg, /hash-refresh verification runs/i); + assert.match(appleDmg, /read-only verification runs/i); +}); diff --git a/scripts/ci/upstream-dmg-acceptance.test.js b/scripts/ci/upstream-dmg-acceptance.test.js index 8c51fc52b..0b6a7415e 100644 --- a/scripts/ci/upstream-dmg-acceptance.test.js +++ b/scripts/ci/upstream-dmg-acceptance.test.js @@ -237,48 +237,36 @@ test("HTTP identity requires an ETag or Last-Modified plus Content-Length", () = assert.ok(httpIdentity({ lastModified: "today", contentLength: 42 })?.key); }); -test("official DMG workflow concurrency is isolated per PR or ref", () => { +test("official DMG workflow is read-only pull-request validation after retirement", () => { const workflow = fs.readFileSync( path.resolve(__dirname, "../../.github/workflows/official-dmg-build-app.yml"), "utf8", ); - assert.match(workflow, /cron: '30 \* \* \* \*'/); + assert.doesNotMatch(workflow, /schedule:/); + assert.doesNotMatch(workflow, /workflow_dispatch:/); + assert.doesNotMatch(workflow, /^\s*push:/m); assert.match( workflow, /group: official-dmg-acceptance-\$\{\{ github\.event_name \}\}-\$\{\{ github\.event\.pull_request\.number \|\| github\.ref \}\}/, ); assert.doesNotMatch(workflow, /group: official-dmg-acceptance-\$\{\{ github\.event_name \}\}\s*$/m); - assert.equal((workflow.match(/- port-integrations\/\*\*/g) ?? []).length, 2); - assert.equal((workflow.match(/- scripts\/lib\/port-integrations\.js/g) ?? []).length, 2); + assert.equal((workflow.match(/- port-integrations\/\*\*/g) ?? []).length, 1); + assert.equal((workflow.match(/- scripts\/lib\/port-integrations\.js/g) ?? []).length, 1); assert.doesNotMatch(workflow, /uses:\s+[^\s]+@v\d/); - assert.match(workflow, /ref: \$\{\{ github\.event\.repository\.default_branch \}\}/); - assert.match(workflow, /persist-credentials: false/); + assert.doesNotMatch(workflow, /issues:\s*write/); + assert.doesNotMatch(workflow, /reconcileUpstreamDmgIssue/); }); -test("Nix refresh serializes campaigns and deduplicates refresh and exact-head CI", () => { - const workflow = fs.readFileSync( - path.resolve(__dirname, "../../.github/workflows/update-chatgpt-hash.yml"), - "utf8", +test("Nix DMG hash refresh workflow remains retired", () => { + assert.equal( + fs.existsSync( + path.resolve(__dirname, "../../.github/workflows/update-chatgpt-hash.yml"), + ), + false, ); - - assert.match(workflow, /expected_main_sha:/); - assert.match(workflow, /expected_dmg_sha256:/); - assert.match(workflow, /run-name: Nix refresh \$\{\{ inputs\.expected_main_sha \}\}:\$\{\{ inputs\.expected_dmg_sha256 \}\}/); - assert.match(workflow, /ref: \$\{\{ inputs\.expected_main_sha \}\}/); - assert.equal((workflow.match(/required: true/g) ?? []).length, 2); - assert.doesNotMatch(workflow, /schedule:/); - assert.doesNotMatch(workflow, /cron:/); - assert.match(workflow, /group: update-nix-official-dmg-hashes/); - assert.match(workflow, /cancel-in-progress: false/); - assert.match(workflow, /Source-Main-SHA:/); - assert.match(workflow, /Source-Main-SHA: \$EXPECTED_MAIN_SHA/); - assert.match(workflow, /Upstream-DMG-SHA256:/); - assert.match(workflow, /git push --force-with-lease origin "\$REFRESH_BRANCH"/); - assert.match(workflow, /Exact-head CI already exists/); - assert.doesNotMatch(workflow, /git push --force origin "\$REFRESH_BRANCH"/); }); -test("Nix hash refresh accepts a validated focused output override", () => { +test("historical Nix hash tooling retains its focused output validation", () => { const script = fs.readFileSync( path.resolve(__dirname, "update-nix-hashes.sh"), "utf8", @@ -287,10 +275,6 @@ test("Nix hash refresh accepts a validated focused output override", () => { path.resolve(__dirname, "../../.github/workflows/ci.yml"), "utf8", ); - const refreshWorkflow = fs.readFileSync( - path.resolve(__dirname, "../../.github/workflows/update-chatgpt-hash.yml"), - "utf8", - ); const watchdogProfile = JSON.parse(fs.readFileSync( path.resolve(__dirname, "watchdog-port-integrations.json"), "utf8", @@ -314,8 +298,6 @@ test("Nix hash refresh accepts a validated focused output override", () => { assert.match(script, /NIX_VERIFY_OUTPUTS/); assert.match(script, /NIX_COMPARE_REF/); assert.match(workflow, /\.#checks\.x86_64-linux\.watchdog-port-integrations/); - assert.match(refreshWorkflow, /NIX_VERIFY_OUTPUTS/); - assert.match(refreshWorkflow, /\.#checks\.x86_64-linux\.watchdog-port-integrations/); assert.match(script, /Invalid Nix verification output/); assert.match(script, /run_nix_build "\$VERIFY_LOG" "\$\{PACKAGE_OUTPUTS\[@\]\}"/); }); diff --git a/scripts/ci/validate-readme-visuals.test.js b/scripts/ci/validate-readme-visuals.test.js index b4bb17725..086f858bc 100644 --- a/scripts/ci/validate-readme-visuals.test.js +++ b/scripts/ci/validate-readme-visuals.test.js @@ -33,45 +33,38 @@ test("accepts the project hero logo and shields.io badges", () => { assert.deepEqual(errorsFor(markdown), []); }); -test("keeps the real README project hero and shield set", () => { +test("keeps the real README project hero and retirement boundary", () => { assert.deepEqual(validateReadmeVisualsContent(readme).errors, []); assert.match( readme, /ChatGPT for Linux project logo/, ); assert.match(readme, /ChatGPT for Linux is an unofficial community project/); - assert.match(readme, /OpenAI has released its official ChatGPT app for Linux in preview/); - assert.match(readme, /If the official release is acceptable, ChatGPT for Linux\s*> will be sunset/); - assert.match(readme, /this project remains a maintained\s*> fallback/); + assert.match(readme, /ChatGPT for Linux is retired and unsupported/); + assert.match(readme, /Do not install or update ChatGPT from this repository/); + assert.doesNotMatch(readme, /remains a maintained\s*> fallback/); assert.match(readme, /`chatgpt-desktop-bin` native repackage/); - assert.match(readme, /both use the `chatgpt` package and command name, so they are mutually\s*exclusive/); - assert.match(readme, /For that CachyOS\/pacman path/); assert.match( readme, - /\[official-app evaluation switch procedure\]\(docs\/maintainers\/package-runtime-maintenance\.md#official-app-evaluation-switch\)/, + /\[official-app parity audit\]\(docs\/maintainers\/research\/official-app-parity-2026-08\.md\)/, ); - assert.match(readme, /OpenAI's official Linux package is\s*not this fork's\s*current build source/); assert.match( readme, - /git clone https:\/\/github\.com\/nisavid\/chatgpt-linux\.git chatgpt-linux\ncd chatgpt-linux/, + /\[rollback-retention boundary\]\(docs\/maintainers\/research\/rollback-evidence-retention-boundary-2026-08\.md\)/, ); assert.doesNotMatch(readme, /nisavid\/codex-app-linux/); assert.match( readme, - /not affiliated\s*> with, endorsed by, sponsored by, or supported by OpenAI/, + /not affiliated\s*with, endorsed by, sponsored by, or supported by OpenAI/, ); - assert.match(readme, /Larry Ewing and\s*> The GIMP, Garrett LeSage, and IFo Hancroft/); + assert.match(readme, /Larry Ewing and The GIMP, Garrett LeSage, and IFo\s*Hancroft/); assert.match( readme, /\[project-logo rights record\]\(docs\/maintainers\/project-logo-rights-research\.md\)/, ); const shields = [...readme.matchAll(/([^/g)] .map((match) => [match[1], match[2]]); - assert.deepEqual(shields, [ - ["Packages: deb, rpm, pacman", "https://img.shields.io/badge/packages-deb%20%7C%20rpm%20%7C%20pacman-2f81f7?style=flat-square"], - ["Updater: chatgpt-updater", "https://img.shields.io/badge/updater-chatgpt--updater-1f883d?style=flat-square"], - ["Focus: hardening and polish", "https://img.shields.io/badge/focus-hardening%20%2B%20polish-8250df?style=flat-square"], - ]); + assert.deepEqual(shields, []); }); test("keeps the approved project SVG and raster logo assets distinct", () => { diff --git a/tests/scripts_smoke.sh b/tests/scripts_smoke.sh index 38ef42125..3ef84dcbb 100755 --- a/tests/scripts_smoke.sh +++ b/tests/scripts_smoke.sh @@ -12578,7 +12578,7 @@ SCRIPT } test_official_dmg_build_app_workflow_tracks_dmg_metadata() { - info "Checking official DMG build-app workflow metadata and cache behavior" + info "Checking retired official DMG pull-request validation metadata" local workflow="$REPO_DIR/.github/workflows/official-dmg-build-app.yml" assert_file_exists "$workflow" @@ -12596,7 +12596,10 @@ test_official_dmg_build_app_workflow_tracks_dmg_metadata() { assert_contains "$workflow" 'make build-app DMG="$OFFICIAL_DMG_PATH"' assert_contains "$workflow" 'official-dmg-decision.json' assert_contains "$workflow" 'accepted|accepted_with_warnings' - assert_contains "$workflow" 'reconcileUpstreamDmgIssue' + assert_not_contains "$workflow" 'schedule:' + assert_not_contains "$workflow" 'workflow_dispatch:' + assert_not_contains "$workflow" 'issues: write' + assert_not_contains "$workflow" 'reconcileUpstreamDmgIssue' } test_installer_writes_package_version_from_app_plist() {