From 735e8dc9d65349d3ce3c16c9257ba9899247065c Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Thu, 25 Jun 2026 13:55:48 +0200 Subject: [PATCH] fix(release): require protected-branch release token Scope protected-main Auto Release credentials to git push by passing RELEASE_PAT as RELEASE_PUSH_TOKEN, clearing it from process.env, and injecting a temporary Git extraheader only for push attempts. Keep checkout persist-credentials=false and fail fast when production push runs lack a nonblank maintainer release token. Improve pm contracts package namespace UX by returning token-efficient command_namespace recovery for namespace roots such as changelog while preserving executable child command flag contracts. Add regression coverage for namespace roots and bounded fallback candidates. Refresh @sentry/node to 10.61.0, keep the generated changelog aligned through pm-changelog, and record PM evidence for pm-9gxi and pm-y1o4 including the remaining external RELEASE_PAT setup state. Verification: focused release/contract tests, full coverage at 100/100/100/100, static/docstring gate at 100%, contracts snapshot check, pm health, changelog check, and manual temp-directory pm smoke. --- .agents/pm/history/pm-9gxi.jsonl | 44 +++ .agents/pm/history/pm-y1o4.jsonl | 19 ++ .agents/pm/issues/pm-9gxi.toon | 45 +++ .agents/pm/issues/pm-y1o4.toon | 26 +- .github/workflows/auto-release.yml | 17 +- CHANGELOG.md | 1 + docs/RELEASING.md | 2 + package.json | 2 +- pnpm-lock.yaml | 278 +++++++++--------- scripts/release/run-release-pipeline.mjs | 31 +- src/cli/commands/contracts.ts | 40 +++ .../integration/ci-workflow-contract.spec.ts | 8 + .../release-automation-contract.spec.ts | 22 -- tests/unit/commands/contracts-command.spec.ts | 143 +++++++++ .../release/run-release-pipeline.spec.ts | 78 +++++ 15 files changed, 586 insertions(+), 170 deletions(-) create mode 100644 .agents/pm/history/pm-9gxi.jsonl create mode 100644 .agents/pm/issues/pm-9gxi.toon diff --git a/.agents/pm/history/pm-9gxi.jsonl b/.agents/pm/history/pm-9gxi.jsonl new file mode 100644 index 000000000..08420ba9f --- /dev/null +++ b/.agents/pm/history/pm-9gxi.jsonl @@ -0,0 +1,44 @@ +{"ts":"2026-06-25T11:02:40.952Z","author":"claude-code-agent","op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-9gxi"},{"op":"add","path":"/metadata/title","value":"Auto Release blocked: bot cannot push version commit to protected main (GH006, 12 required checks)"},{"op":"add","path":"/metadata/description","value":"The daily Auto Release (.github/workflows/auto-release.yml -> scripts/release/run-release-pipeline.mjs) failed on 2026-06-25 (run 28151547639). ALL gates passed (250 test files, Sentry/telemetry reliability gate green, static/docs/compat) — the failure is the final step pushReleaseRefs: 'git push --atomic origin HEAD v2026.6.25' is rejected with 'remote: error: GH006: Protected branch update failed for refs/heads/main'. The pipeline creates a version-bump commit (git add package.json CHANGELOG.md + commit, run-release-pipeline.mjs:395) and pushes that fresh commit to main. main's branch protection requires 12 status checks (Build foundation, Runtime smoke x3, Gates x5, Windows regression (Node 24), Docs and Skills, Analyze) and enforce_admins=false. The github-actions bot using GITHUB_TOKEN is NOT an admin, so its direct push of an unchecked commit is rejected; an admin push (owner) bypasses (enforce_admins=false), which is why manual pushes succeed. This worked through 2026-06-24 and regressed 2026-06-25, consistent with required checks being added/enforced on main (the Windows regression check is recent). Net effect: npm is stuck at 2026.6.24 while version:next=2026.6.25; releasable changes (incl. the GH-363 Windows fix in #365) are not being published. Secondary: the 'Auto Release blocked' alert's gh issue create failed that run with 'Resource not accessible by integration (createIssue)' ONLY because pm-qawd/#364 (issues:write) merged at 08:40Z, after the 06:32Z run — issues:write is now on main so the alert will fire on the next scheduled run. REMEDIATION OPTIONS (owner decision; requires a secret or a security-posture change): (1) RECOMMENDED — add a fine-grained PAT secret (e.g. RELEASE_PAT) from an admin with contents:write, and have the auto-release checkout use token: ${{ secrets.RELEASE_PAT || github.token }} so the version-commit push bypasses required checks like an admin; no-regression fallback to GITHUB_TOKEN when unset. (2) Migrate main to a repository ruleset with a bypass actor for the release workflow/bot. (3) Stop committing to main during release — derive the version from the calendar tag only and push just the tag (tags are not branch-protected), moving CHANGELOG regeneration to the existing chore-commit flow. Until resolved, releases can be cut manually by an admin running release:pipeline locally."},{"op":"add","path":"/metadata/type","value":"Issue"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":1},{"op":"add","path":"/metadata/tags","value":["area:ci","auto-release","branch-protection","release","reliability"]},{"op":"add","path":"/metadata/created_at","value":"2026-06-25T11:02:40.952Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-06-25T11:02:40.952Z"},{"op":"add","path":"/metadata/author","value":"claude-code-agent"},{"op":"add","path":"/metadata/parent","value":"pm-u9d0"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"a23a47300e43a9378a6ee2134c94350f92711e33b9499f2663c0eb349231dd35","message":""} +{"ts":"2026-06-25T11:02:54.142Z","author":"claude-code-agent","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:02:54.142Z"},{"op":"add","path":"/metadata/dependencies","value":[{"id":"pm-7zs0","kind":"related","created_at":"2026-06-25T11:02:54.128Z"}]}],"before_hash":"a23a47300e43a9378a6ee2134c94350f92711e33b9499f2663c0eb349231dd35","after_hash":"80771fa0bb948a94efdbbaa8af0d7208ffcbdd7f8ee11f6627745f5907a6a8d9"} +{"ts":"2026-06-25T11:02:54.444Z","author":"claude-code-agent","op":"update","patch":[{"op":"add","path":"/metadata/dependencies/1","value":{"id":"pm-nb08","kind":"related","created_at":"2026-06-25T11:02:54.430Z"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:02:54.444Z"}],"before_hash":"80771fa0bb948a94efdbbaa8af0d7208ffcbdd7f8ee11f6627745f5907a6a8d9","after_hash":"461fc505abf4e2cdcfae45e57d6f12251e9ed9ccea7f29adba6e4d084ee98cba"} +{"ts":"2026-06-25T11:20:06.837Z","author":"codex-20260625","op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:20:06.837Z"},{"op":"add","path":"/metadata/assignee","value":"codex-20260625"}],"before_hash":"461fc505abf4e2cdcfae45e57d6f12251e9ed9ccea7f29adba6e4d084ee98cba","after_hash":"ca8f1e098e3a6fa78877b69f2a30ad11ca398d6e586eb62b7827a84da5d00e1c"} +{"ts":"2026-06-25T11:23:26.402Z","author":"codex-20260625","op":"update_audit","patch":[{"op":"add","path":"/metadata/dependencies/2","value":{"id":"pm-y1o4","kind":"related","created_at":"2026-06-25T11:23:26.383Z"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:23:26.402Z"}],"before_hash":"ca8f1e098e3a6fa78877b69f2a30ad11ca398d6e586eb62b7827a84da5d00e1c","after_hash":"f519d28e63b2858b0edf85bd29cdac2d40c056d0f44c7092bb75b9997569c0c3","message":"Bundle adjacent agent-facing release and package-contract reliability fixes in one PR."} +{"ts":"2026-06-25T11:25:35.379Z","author":"codex-20260625","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:25:35.379Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"f519d28e63b2858b0edf85bd29cdac2d40c056d0f44c7092bb75b9997569c0c3","after_hash":"6400c880ca45d3cc779f4564a59cf2c1cb61413308afd2ff1c3c45e63a329848","message":"Start protected-branch Auto Release remediation."} +{"ts":"2026-06-25T11:25:35.619Z","author":"codex-20260625","op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:25:35.619Z"},{"op":"add","path":"/metadata/files","value":[{"path":".github/workflows/auto-release.yml","scope":"project","note":"wire RELEASE_PAT checkout token and push preflight"}]}],"before_hash":"6400c880ca45d3cc779f4564a59cf2c1cb61413308afd2ff1c3c45e63a329848","after_hash":"70783a5cdfd30394706e543c9a0780530cbf0042ef013d0df9b5a45945d34828"} +{"ts":"2026-06-25T11:25:48.917Z","author":"codex-20260625","op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:25:48.917Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/RELEASING.md","scope":"project","note":"document release push token setup and fail-fast policy"}]}],"before_hash":"70783a5cdfd30394706e543c9a0780530cbf0042ef013d0df9b5a45945d34828","after_hash":"c46d6109d1dbb810a2c815743b48cb392303f31e26be0e5c275f43e0da89637b"} +{"ts":"2026-06-25T11:25:59.822Z","author":"codex-20260625","op":"files_add","patch":[{"op":"add","path":"/metadata/files/1","value":{"path":"tests/integration/release-automation-contract.spec.ts","scope":"project","note":"assert auto-release RELEASE_PAT contract"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:25:59.822Z"}],"before_hash":"c46d6109d1dbb810a2c815743b48cb392303f31e26be0e5c275f43e0da89637b","after_hash":"a7304ccf17c31d08446bca29e71d243aaa333fb5374e3d6917405ec4b35c3ffe"} +{"ts":"2026-06-25T11:26:04.638Z","author":"codex-20260625","op":"files_add","patch":[{"op":"replace","path":"/metadata/files/1/note","value":"assert auto-release workflow token and alert contract"},{"op":"replace","path":"/metadata/files/1/path","value":"tests/integration/ci-workflow-contract.spec.ts"},{"op":"add","path":"/metadata/files/2","value":{"path":"tests/integration/release-automation-contract.spec.ts","scope":"project","note":"assert auto-release RELEASE_PAT contract"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:26:04.638Z"}],"before_hash":"a7304ccf17c31d08446bca29e71d243aaa333fb5374e3d6917405ec4b35c3ffe","after_hash":"ef79db0c8454c17ffb21bac07bfaba107c51a3c9800e4e642ca097af2b75e7b4"} +{"ts":"2026-06-25T11:26:08.836Z","author":"codex-20260625","op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:26:08.836Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node scripts/run-tests.mjs test -- tests/integration/release-automation-contract.spec.ts tests/integration/ci-workflow-contract.spec.ts","scope":"project","timeout_seconds":240}]}],"before_hash":"ef79db0c8454c17ffb21bac07bfaba107c51a3c9800e4e642ca097af2b75e7b4","after_hash":"3126ff560cfe8b5be57e065155c7b7e7a98cc4db03ad6d4c656dd517e5661a8e"} +{"ts":"2026-06-25T11:26:27.466Z","author":"codex-20260625","op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:26:27.466Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mqtf2n44-55ns6h","kind":"test","status":"passed","started_at":"2026-06-25T11:26:22.261Z","finished_at":"2026-06-25T11:26:27.461Z","recorded_at":"2026-06-25T11:26:27.461Z","passed":1,"failed":0,"skipped":0}]}],"before_hash":"3126ff560cfe8b5be57e065155c7b7e7a98cc4db03ad6d4c656dd517e5661a8e","after_hash":"ea260deb2302afe2992531bc8064cbecab8c70d3141939a793dda85373f8f8c2","message":"Track test run summary (test-local-mqtf2n44-55ns6h)"} +{"ts":"2026-06-25T11:37:33.960Z","author":"codex-20260625","op":"files_add","patch":[{"op":"replace","path":"/metadata/files/2/note","value":"assert auto-release workflow token and alert contract"},{"op":"replace","path":"/metadata/files/2/path","value":"tests/integration/ci-workflow-contract.spec.ts"},{"op":"replace","path":"/metadata/files/1/note","value":"refresh @sentry/node dependency for release reliability"},{"op":"replace","path":"/metadata/files/1/path","value":"package.json"},{"op":"add","path":"/metadata/files/3","value":{"path":"tests/integration/release-automation-contract.spec.ts","scope":"project","note":"assert auto-release RELEASE_PAT contract"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:37:33.960Z"}],"before_hash":"ea260deb2302afe2992531bc8064cbecab8c70d3141939a793dda85373f8f8c2","after_hash":"55d850936ac88738d362b4c6110dc65d38c7f3ab953d0801613c535aae0883d4"} +{"ts":"2026-06-25T11:37:38.814Z","author":"codex-20260625","op":"files_add","patch":[{"op":"replace","path":"/metadata/files/3/note","value":"assert auto-release workflow token and alert contract"},{"op":"replace","path":"/metadata/files/3/path","value":"tests/integration/ci-workflow-contract.spec.ts"},{"op":"replace","path":"/metadata/files/2/note","value":"lock @sentry/node 10.61.0 dependency graph"},{"op":"replace","path":"/metadata/files/2/path","value":"pnpm-lock.yaml"},{"op":"add","path":"/metadata/files/4","value":{"path":"tests/integration/release-automation-contract.spec.ts","scope":"project","note":"assert auto-release RELEASE_PAT contract"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:37:38.814Z"}],"before_hash":"55d850936ac88738d362b4c6110dc65d38c7f3ab953d0801613c535aae0883d4","after_hash":"7e5fda672d800621bc3dbefb801fb0cce46f5482ec473c70029f453dec9969d1"} +{"ts":"2026-06-25T11:52:42.705Z","author":"codex-20260625","op":"tests_add","patch":[{"op":"replace","path":"/metadata/tests/0/timeout_seconds","value":900},{"op":"replace","path":"/metadata/tests/0/command","value":"node scripts/release/run-gates.mjs --json --telemetry-mode off"},{"op":"add","path":"/metadata/tests/1","value":{"command":"node scripts/run-tests.mjs test -- tests/integration/release-automation-contract.spec.ts tests/integration/ci-workflow-contract.spec.ts","scope":"project","timeout_seconds":240}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:52:42.705Z"}],"before_hash":"7e5fda672d800621bc3dbefb801fb0cce46f5482ec473c70029f453dec9969d1","after_hash":"5b8fdbd0c36a478e022df9e86e0607032173ccfeeccf1d204e4eceea0c97ed58"} +{"ts":"2026-06-25T11:52:46.783Z","author":"codex-20260625","op":"tests_add","patch":[{"op":"replace","path":"/metadata/tests/1/timeout_seconds","value":180},{"op":"replace","path":"/metadata/tests/1/command","value":"node scripts/release/sentry-telemetry-gate.mjs --json --telemetry-mode best-effort"},{"op":"add","path":"/metadata/tests/2","value":{"command":"node scripts/run-tests.mjs test -- tests/integration/release-automation-contract.spec.ts tests/integration/ci-workflow-contract.spec.ts","scope":"project","timeout_seconds":240}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:52:46.783Z"}],"before_hash":"5b8fdbd0c36a478e022df9e86e0607032173ccfeeccf1d204e4eceea0c97ed58","after_hash":"6fc40ff280e0b1ea575fc2623611865f891bc206f1acba8fa31fe7c0762d6501"} +{"ts":"2026-06-25T11:52:52.268Z","author":"codex-20260625","op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/3","value":{"command":"pnpm audit --audit-level low","scope":"project","timeout_seconds":120}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:52:52.268Z"}],"before_hash":"6fc40ff280e0b1ea575fc2623611865f891bc206f1acba8fa31fe7c0762d6501","after_hash":"f2fd8af383cd4e10d74959c74b100d4cd611201b7c1373478c5b8991280fc270"} +{"ts":"2026-06-25T11:52:55.938Z","author":"codex-20260625","op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/4","value":{"command":"pnpm security:scan","scope":"project","timeout_seconds":120}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:52:55.938Z"}],"before_hash":"f2fd8af383cd4e10d74959c74b100d4cd611201b7c1373478c5b8991280fc270","after_hash":"b5fb34636bb6da26cb8842939ffbf5cf2428e196ca1a16b4c526a548a9729004"} +{"ts":"2026-06-25T11:53:04.258Z","author":"codex-20260625","op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:53:04.258Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-06-25T11:53:04.258Z","author":"codex-20260625","text":"Evidence: implemented RELEASE_PAT checkout token fallback, production push preflight, and blocked-release alert guidance; documented release environment setup. Verification passed: focused workflow tests (21 tests), full run-gates with telemetry-mode off (build/typecheck/docs/static/coverage/version/secret-scan/npx/package dogfood/npm pack/compat/Sentry all ok), live Sentry/telemetry gate best-effort (Sentry critical=0 high=0, telemetry finish_error_rate_pct=0.78, missing error-code rows=0), pnpm audit low clean, pnpm security:scan clean, no open GitHub PRs/issues/Dependabot/secret alerts. Manual temp smoke passed in /tmp/pm-cli-manual-smoke-NS6WJB with create/claim/update/files/docs/tests/comment/list/validate/health/close/release under sandboxed PM_PATH and PM_GLOBAL_PATH. Remaining external setup: release environment currently has NPM_TOKEN, SENTRY_AUTH_TOKEN, and SENTRY_PERSONAL_ADMIN_TOKEN, but no RELEASE_PAT; scheduled Auto Release will now fail fast until that maintainer token is configured."}]}],"before_hash":"b5fb34636bb6da26cb8842939ffbf5cf2428e196ca1a16b4c526a548a9729004","after_hash":"e00a6c6f150e94fa01bb87c9b030a7068b31aee87c028070480436d892c1f421"} +{"ts":"2026-06-25T11:55:10.539Z","author":"codex-20260625","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:55:10.539Z"},{"op":"add","path":"/metadata/expected_result","value":"Auto Release production runs use a configured maintainer RELEASE_PAT to push the checked version commit and tag to protected main after gates pass, and missing release credentials fail fast with clear recovery guidance."},{"op":"add","path":"/metadata/actual_result","value":"Workflow code now uses secrets.RELEASE_PAT || github.token, validates production push runs before expensive release gates, and documents the release environment requirement; the current release environment still lacks RELEASE_PAT, so scheduled release remains blocked on external secret configuration."}],"before_hash":"e00a6c6f150e94fa01bb87c9b030a7068b31aee87c028070480436d892c1f421","after_hash":"5f4f5d01fd205264a3a4a9e04fb1ef0089e6bcecda43ed61ac8e791e93e7a9c1","message":"Record auto-release secret setup state"} +{"ts":"2026-06-25T11:55:14.201Z","author":"codex-20260625","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:55:14.201Z"},{"op":"replace","path":"/metadata/status","value":"blocked"}],"before_hash":"5f4f5d01fd205264a3a4a9e04fb1ef0089e6bcecda43ed61ac8e791e93e7a9c1","after_hash":"1395a4a31f6e41ef89fb52afe39340c634ab90e6a52cef8280ef2331ec1c1ed9","message":"Code path is implemented and verified; blocked on configuring RELEASE_PAT in the release environment."} +{"ts":"2026-06-25T11:55:18.845Z","author":"codex-20260625","op":"release","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:55:18.845Z"}],"before_hash":"1395a4a31f6e41ef89fb52afe39340c634ab90e6a52cef8280ef2331ec1c1ed9","after_hash":"8688b984fc3f2e3596e9d5e9321480ae79ef04829557b084039ef7998b1dfeda"} +{"ts":"2026-06-25T12:24:11.367Z","author":"codex-20260625","op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:24:11.367Z"},{"op":"add","path":"/metadata/assignee","value":"codex-20260625"}],"before_hash":"8688b984fc3f2e3596e9d5e9321480ae79ef04829557b084039ef7998b1dfeda","after_hash":"f142e4e79c69f122e02b2b56f91ce4e07f2a616a9b1f855b2a2fd31a7d01c8a3"} +{"ts":"2026-06-25T12:24:20.852Z","author":"codex-20260625","op":"files_add","patch":[{"op":"replace","path":"/metadata/files/4/note","value":"assert auto-release workflow token and alert contract"},{"op":"replace","path":"/metadata/files/4/path","value":"tests/integration/ci-workflow-contract.spec.ts"},{"op":"replace","path":"/metadata/files/3/note","value":"scope RELEASE_PUSH_TOKEN to git push only"},{"op":"replace","path":"/metadata/files/3/path","value":"scripts/release/run-release-pipeline.mjs"},{"op":"add","path":"/metadata/files/5","value":{"path":"tests/integration/release-automation-contract.spec.ts","scope":"project","note":"assert auto-release RELEASE_PAT contract"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:24:20.852Z"}],"before_hash":"f142e4e79c69f122e02b2b56f91ce4e07f2a616a9b1f855b2a2fd31a7d01c8a3","after_hash":"49953744ca29080aa0032cbc207d57d285a0da6fafff319162dbd86622c7dc13"} +{"ts":"2026-06-25T12:24:25.434Z","author":"codex-20260625","op":"files_add","patch":[{"op":"add","path":"/metadata/files/6","value":{"path":"tests/unit/scripts/release/run-release-pipeline.spec.ts","scope":"project","note":"cover release push token scoping"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:24:25.434Z"}],"before_hash":"49953744ca29080aa0032cbc207d57d285a0da6fafff319162dbd86622c7dc13","after_hash":"e28b509ee2852438c12f3d88655f30d4f91ba0b611c86d713fe8cc474df1939d"} +{"ts":"2026-06-25T12:24:32.607Z","author":"codex-20260625","op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:24:32.607Z"}],"before_hash":"e28b509ee2852438c12f3d88655f30d4f91ba0b611c86d713fe8cc474df1939d","after_hash":"146f8eac9467bdf3d1705bfe82fc842691e54f3e8c715456e8e288072b5a2cb5"} +{"ts":"2026-06-25T12:24:39.224Z","author":"codex-20260625","op":"tests_add","patch":[{"op":"replace","path":"/metadata/tests/4/command","value":"pnpm audit --audit-level low"},{"op":"replace","path":"/metadata/tests/3/timeout_seconds","value":240},{"op":"replace","path":"/metadata/tests/3/command","value":"node scripts/run-tests.mjs test -- tests/unit/scripts/release/run-release-pipeline.spec.ts tests/integration/ci-workflow-contract.spec.ts tests/integration/release-automation-contract.spec.ts tests/unit/commands/contracts-command.spec.ts"},{"op":"add","path":"/metadata/tests/5","value":{"command":"pnpm security:scan","scope":"project","timeout_seconds":120}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:24:39.224Z"}],"before_hash":"146f8eac9467bdf3d1705bfe82fc842691e54f3e8c715456e8e288072b5a2cb5","after_hash":"2bafc407734fee03ff10973921480823f493ed6a7128a5184c5bf94e63dd25cd"} +{"ts":"2026-06-25T12:24:45.475Z","author":"codex-20260625","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-06-25T12:24:45.475Z","author":"codex-20260625","text":"Review response: addressed CodeRabbit security finding by setting checkout persist-credentials=false, passing RELEASE_PUSH_TOKEN only to run-release-pipeline, deleting it from process.env before child gates run, and injecting a Git extraheader only for git push. Addressed Gemini maintainability feedback by removing the duplicate auto-release workflow assertion block from release-automation-contract.spec.ts and keeping the comprehensive CI workflow contract as the single workflow surface check. Verification: focused review-response tests passed 90 tests; run-release-pipeline unit test passed 33 tests; full coverage passed 100/100/100/100 (5097 tests)."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:24:45.475Z"}],"before_hash":"2bafc407734fee03ff10973921480823f493ed6a7128a5184c5bf94e63dd25cd","after_hash":"3b18dcff6120ab959725c22348a381f0353a88fbbda111073eb2046604446a3b"} +{"ts":"2026-06-25T12:24:53.342Z","author":"codex-20260625","op":"update","patch":[{"op":"replace","path":"/metadata/actual_result","value":"Workflow code now validates production push runs before expensive release gates, does not persist elevated checkout credentials, passes RELEASE_PUSH_TOKEN only into run-release-pipeline, deletes it from child process inheritance, and injects git push auth through a per-push extraheader; docs capture the setup requirement. The current release environment still lacks RELEASE_PAT, so scheduled release remains blocked on external secret configuration."},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:24:53.342Z"}],"before_hash":"3b18dcff6120ab959725c22348a381f0353a88fbbda111073eb2046604446a3b","after_hash":"796381c1abac4cc6b8590da3edd59e9247568b2dc51db38cefdba6d49746e9e5","message":"Record scoped release token implementation"} +{"ts":"2026-06-25T12:25:06.766Z","author":"codex-20260625","op":"release","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:25:06.766Z"}],"before_hash":"796381c1abac4cc6b8590da3edd59e9247568b2dc51db38cefdba6d49746e9e5","after_hash":"3dd5004a5fb6547d4f54e260dabbf2f31abc76c195fd4d38846dedb08ab7a27c"} +{"ts":"2026-06-25T12:33:56.310Z","author":"codex-gpt5","op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:33:56.310Z"},{"op":"add","path":"/metadata/assignee","value":"codex-gpt5"}],"before_hash":"3dd5004a5fb6547d4f54e260dabbf2f31abc76c195fd4d38846dedb08ab7a27c","after_hash":"e1a5ca3f6ae75161b95dee0dfc0b6848f2b2675cb747c6ae3f27d12daed2cdd8"} +{"ts":"2026-06-25T12:33:56.642Z","author":"codex-gpt5","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:33:56.642Z"}],"before_hash":"e1a5ca3f6ae75161b95dee0dfc0b6848f2b2675cb747c6ae3f27d12daed2cdd8","after_hash":"c4a00977cfc63c286ccbb0e62ec51382433b5ce05a492f9bce46ca3efef96d54","message":"Address fresh Gemini review on PR #366: standardize git push auth header casing while keeping release token scoped to push only."} +{"ts":"2026-06-25T12:38:47.894Z","author":"codex-gpt5","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-06-25T12:38:47.894Z","author":"codex-gpt5","text":"Review response follow-up: accepted Gemini compatibility feedback and standardized the temporary git push auth extraheader to 'Authorization: Basic' while preserving per-push RELEASE_PUSH_TOKEN scoping and checkout persist-credentials=false. Verification passed after the patch: node scripts/run-tests.mjs test -- tests/unit/scripts/release/run-release-pipeline.spec.ts (33 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5097 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, changelog --check unchanged, pm health summary ok, git diff --check clean."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:38:47.894Z"}],"before_hash":"c4a00977cfc63c286ccbb0e62ec51382433b5ce05a492f9bce46ca3efef96d54","after_hash":"3e7975d3679139c78b03c6512ffe5fe917ae4c7a6762a27f1b88abaafc7d2e98"} +{"ts":"2026-06-25T12:38:48.216Z","author":"codex-gpt5","op":"release","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:38:48.216Z"}],"before_hash":"3e7975d3679139c78b03c6512ffe5fe917ae4c7a6762a27f1b88abaafc7d2e98","after_hash":"0c66fc00f8ca2aa33029207e4510fd9b3a92d1bcd87c4eb8a21a5cb02205a2f7"} +{"ts":"2026-06-25T12:46:37.271Z","author":"codex-gpt5","op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:46:37.271Z"},{"op":"add","path":"/metadata/assignee","value":"codex-gpt5"}],"before_hash":"0c66fc00f8ca2aa33029207e4510fd9b3a92d1bcd87c4eb8a21a5cb02205a2f7","after_hash":"49fbf8e591ad9fe7123ee6be5ac3a0e607e490fe4886c928ac0435cf0df7c0f0"} +{"ts":"2026-06-25T12:46:37.608Z","author":"codex-gpt5","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:46:37.608Z"}],"before_hash":"49fbf8e591ad9fe7123ee6be5ac3a0e607e490fe4886c928ac0435cf0df7c0f0","after_hash":"b90cd5a94efffdb761fd42b2072d76b145c54e618ad8a51d978bccfff5ddb1f6","message":"Address fresh Gemini review on PR #366: append RELEASE_PUSH_TOKEN git extraheader to existing GIT_CONFIG_* env instead of hardcoding slot 0."} +{"ts":"2026-06-25T12:55:03.184Z","author":"codex-gpt5","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-06-25T12:55:03.184Z","author":"codex-gpt5","text":"Review response follow-up: accepted Gemini feedback to append RELEASE_PUSH_TOKEN's git extraheader after any existing GIT_CONFIG_* env entries instead of hardcoding slot 0. Added unit coverage for empty, malformed, and pre-existing Git config env cases. Verification passed: node scripts/run-tests.mjs test -- tests/unit/scripts/release/run-release-pipeline.spec.ts (33 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5097 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, changelog --check unchanged, pm health summary ok, git diff --check clean."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:55:03.184Z"}],"before_hash":"b90cd5a94efffdb761fd42b2072d76b145c54e618ad8a51d978bccfff5ddb1f6","after_hash":"251bcb6789da78abb5b54c28873ec7e15d7895bbc7d85643c24dd25d519b290c"} +{"ts":"2026-06-25T12:55:03.483Z","author":"codex-gpt5","op":"release","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:55:03.483Z"}],"before_hash":"251bcb6789da78abb5b54c28873ec7e15d7895bbc7d85643c24dd25d519b290c","after_hash":"68cf87ff0fffc417057b34e24c96b9d8269a4fec645bc7276dc2fa7e8c4a6263"} +{"ts":"2026-06-25T13:04:02.471Z","author":"codex-gpt5","op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:04:02.471Z"},{"op":"add","path":"/metadata/assignee","value":"codex-gpt5"}],"before_hash":"68cf87ff0fffc417057b34e24c96b9d8269a4fec645bc7276dc2fa7e8c4a6263","after_hash":"f59b48ee5eaca9047b4674d696815bcc5e6635cc52af98a2d41fd8910d8cc859"} +{"ts":"2026-06-25T13:04:02.793Z","author":"codex-gpt5","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:04:02.793Z"}],"before_hash":"f59b48ee5eaca9047b4674d696815bcc5e6635cc52af98a2d41fd8910d8cc859","after_hash":"3302e7b5cb4a86cd3f9dc0bbbcd1c3dc0ae82e875840a4af59b06873fba94310","message":"Address latest CodeRabbit review on PR #366: align Auto Release workflow preflight with trimmed RELEASE_PUSH_TOKEN so blank RELEASE_PAT fails early."} +{"ts":"2026-06-25T13:08:46.131Z","author":"codex-gpt5","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-06-25T13:08:46.131Z","author":"codex-gpt5","text":"Review response follow-up: accepted CodeRabbit finding and aligned the Auto Release workflow preflight with run-release-pipeline's trimmed RELEASE_PUSH_TOKEN behavior. Push-mode releases now fail fast when RELEASE_PAT is absent or when the effective RELEASE_PUSH_TOKEN is whitespace-only, before expensive release work and before a late git push failure. Added ci-workflow contract coverage for the trimmed token guard. Verification passed: focused workflow/release tests (40 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5097 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, changelog --check unchanged, pm health summary ok, git diff --check clean."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:08:46.131Z"}],"before_hash":"3302e7b5cb4a86cd3f9dc0bbbcd1c3dc0ae82e875840a4af59b06873fba94310","after_hash":"7d2d73217a876febfefdd47f58da0151f791907dca285f577cd3cd8f98bf0ace"} +{"ts":"2026-06-25T13:08:46.477Z","author":"codex-gpt5","op":"release","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:08:46.477Z"}],"before_hash":"7d2d73217a876febfefdd47f58da0151f791907dca285f577cd3cd8f98bf0ace","after_hash":"d7a4124387fb656da7b13be0af5babb162c0d2680cd2387298aeeb7aecde89d7"} +{"ts":"2026-06-25T13:31:24.206Z","author":"codex-gpt5","op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:31:24.206Z"},{"op":"add","path":"/metadata/assignee","value":"codex-gpt5"}],"before_hash":"d7a4124387fb656da7b13be0af5babb162c0d2680cd2387298aeeb7aecde89d7","after_hash":"00d22b6414bf2bc4b3b08edeb2196850b3d39cdb2b20cc3c0fb3480051394659"} +{"ts":"2026-06-25T13:35:48.242Z","author":"codex-gpt5","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-06-25T13:35:48.242Z","author":"codex-gpt5","text":"Review response follow-up: accepted Gemini defensive-programming feedback for withReleasePushCredentials by normalizing explicit null gitOptions before reading env, while preserving existing env merge and RELEASE_PUSH_TOKEN push-only scoping. Added unit coverage for null gitOptions. Verification passed: node scripts/run-tests.mjs test -- tests/unit/scripts/release/run-release-pipeline.spec.ts (33 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5098 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, git diff --check clean."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:35:48.242Z"}],"before_hash":"00d22b6414bf2bc4b3b08edeb2196850b3d39cdb2b20cc3c0fb3480051394659","after_hash":"d4908b46b924970141f017c7ac0714c20723b6a986fed251fb8d30a1d06ae410"} diff --git a/.agents/pm/history/pm-y1o4.jsonl b/.agents/pm/history/pm-y1o4.jsonl index d2c023a86..1c8085316 100644 --- a/.agents/pm/history/pm-y1o4.jsonl +++ b/.agents/pm/history/pm-y1o4.jsonl @@ -1 +1,20 @@ {"ts":"2026-06-25T04:53:47.719Z","author":"codex-pm-ecosystem-audit-20260625","op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-y1o4"},{"op":"add","path":"/metadata/title","value":"Contracts command lookup should handle package namespace roots"},{"op":"add","path":"/metadata/description","value":"The 2026-06-25 source-map audit found that an installed package namespace can expose help at the root command path while pm contracts --command reports unknown_command; child command lookup works."},{"op":"add","path":"/metadata/type","value":"Issue"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":["agent-ux","area:contracts","area:mcp","area:packages"]},{"op":"add","path":"/metadata/created_at","value":"2026-06-25T04:53:47.719Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-06-25T04:53:47.719Z"},{"op":"add","path":"/metadata/author","value":"codex-pm-ecosystem-audit-20260625"},{"op":"add","path":"/metadata/estimated_minutes","value":120},{"op":"add","path":"/metadata/acceptance_criteria","value":"The intended contract behavior for package namespace roots is defined; pm contracts either returns namespace metadata/child-command guidance for roots like changelog or emits a clearer package-namespace error; regression coverage exercises installed package namespace root and child command; pnpm contracts:check and package command discovery tests pass."},{"op":"add","path":"/metadata/parent","value":"pm-5k4v"},{"op":"add","path":"/metadata/repro_steps","value":"Run node dist/cli.js changelog --help, then node dist/cli.js contracts --command changelog --flags-only --json and node dist/cli.js contracts --command \"changelog generate\" --flags-only --json."},{"op":"add","path":"/metadata/expected_result","value":"Contracts lookup gives useful namespace-level metadata or a precise guidance error for the package namespace root, while child command lookup remains valid."},{"op":"add","path":"/metadata/actual_result","value":"Root namespace help exists, but contracts --command changelog returns unknown_command; contracts --command \"changelog generate\" works."},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-06-25T04:53:47.719Z","author":"codex-pm-ecosystem-audit-20260625","text":"Duplicate check before create: status-all search for contracts --command changelog unknown_command package root command full path changelog generate found related closed items pm-7etc, pm-4os2/pm-d6kq class work, and pm-zqes class work, but no open direct namespace-root contracts item."}]}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"da1266e103d3eaafc6bd1daa7bb4a1c90eb7208b3a779e90e411562839e865cf","message":"Create package namespace contracts tracking issue"} +{"ts":"2026-06-25T11:23:05.340Z","author":"codex-20260625","op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:23:05.340Z"},{"op":"add","path":"/metadata/assignee","value":"codex-20260625"}],"before_hash":"da1266e103d3eaafc6bd1daa7bb4a1c90eb7208b3a779e90e411562839e865cf","after_hash":"4fbc3f60bc75472c67253d23e466f7b6fcd012bfc60cccad7f4cf79934c7099c"} +{"ts":"2026-06-25T11:25:35.391Z","author":"codex-20260625","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:25:35.391Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"4fbc3f60bc75472c67253d23e466f7b6fcd012bfc60cccad7f4cf79934c7099c","after_hash":"b9e0ed0ea71661360c525c589689059ba10e1ded02da1501e80706ddc9e820fb","message":"Start package namespace contracts remediation."} +{"ts":"2026-06-25T11:25:35.678Z","author":"codex-20260625","op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:25:35.678Z"},{"op":"add","path":"/metadata/files","value":[{"path":"tests/unit/commands/contracts-command.spec.ts","scope":"project","note":"regress namespace root and child command contract behavior"}]}],"before_hash":"b9e0ed0ea71661360c525c589689059ba10e1ded02da1501e80706ddc9e820fb","after_hash":"a36e8cff414b0150f21b7476449fe1aa45a2970ad53caf56a77551ec96746435"} +{"ts":"2026-06-25T11:25:35.702Z","author":"codex-20260625","op":"files_add","patch":[{"op":"replace","path":"/metadata/files/0/note","value":"emit command_namespace guidance for package command roots"},{"op":"replace","path":"/metadata/files/0/path","value":"src/cli/commands/contracts.ts"},{"op":"add","path":"/metadata/files/1","value":{"path":"tests/unit/commands/contracts-command.spec.ts","scope":"project","note":"regress namespace root and child command contract behavior"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:25:35.702Z"}],"before_hash":"a36e8cff414b0150f21b7476449fe1aa45a2970ad53caf56a77551ec96746435","after_hash":"2df9bbe7314bd3b99a6151c1e25d2c10a0b88a9016db969bf3ebfb42d0e09640"} +{"ts":"2026-06-25T11:26:13.670Z","author":"codex-20260625","op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:26:13.670Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node scripts/run-tests.mjs test -- tests/unit/commands/contracts-command.spec.ts","scope":"project","timeout_seconds":240}]}],"before_hash":"2df9bbe7314bd3b99a6151c1e25d2c10a0b88a9016db969bf3ebfb42d0e09640","after_hash":"4d924f41946352e42cfda11a9473faf3c8c07b767f28c818873e543b731c2587"} +{"ts":"2026-06-25T11:26:39.265Z","author":"codex-20260625","op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:26:39.265Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mqtf2w7w-ehc5qs","kind":"test","status":"passed","started_at":"2026-06-25T11:26:32.946Z","finished_at":"2026-06-25T11:26:39.260Z","recorded_at":"2026-06-25T11:26:39.260Z","passed":1,"failed":0,"skipped":0}]}],"before_hash":"4d924f41946352e42cfda11a9473faf3c8c07b767f28c818873e543b731c2587","after_hash":"cd5f64e4992f671e5aaa9ba509d37969553538947da285ae7cb1bd045b96ed96","message":"Track test run summary (test-local-mqtf2w7w-ehc5qs)"} +{"ts":"2026-06-25T11:52:09.763Z","author":"codex-20260625","op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"pnpm contracts:check","scope":"project","timeout_seconds":240}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:52:09.763Z"}],"before_hash":"cd5f64e4992f671e5aaa9ba509d37969553538947da285ae7cb1bd045b96ed96","after_hash":"3dc85764b1d98ab7177666b292f3c0ada364c2451b16dbe2911b2e31c12275da"} +{"ts":"2026-06-25T11:52:14.770Z","author":"codex-20260625","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-06-25T11:52:14.770Z","author":"codex-20260625","text":"Evidence: implemented command_namespace guidance for package namespace roots in contracts lookup; added regression coverage for changelog namespace roots and child commands. Verification passed: node scripts/run-tests.mjs test -- tests/unit/commands/contracts-command.spec.ts (36 tests), pnpm contracts:check, node scripts/run-tests.mjs coverage (100/100/100/100), static-quality gate docstrings 237/237 source and 1840/1840 exported."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:52:14.770Z"}],"before_hash":"3dc85764b1d98ab7177666b292f3c0ada364c2451b16dbe2911b2e31c12275da","after_hash":"876076a7415e2f76d6b9f9856ec8d0c970652d0ebc3ac34182306ba0f0e1e7d0"} +{"ts":"2026-06-25T11:52:21.279Z","author":"codex-20260625","op":"update","patch":[{"op":"replace","path":"/metadata/actual_result","value":"pm contracts --command changelog now reports command_namespace with concrete changelog export/generate retry examples; changelog generate/export child lookups return extension-provided flag contracts."},{"op":"replace","path":"/metadata/expected_result","value":"pm contracts --command gives precise child-command guidance instead of unknown_command, while pm contracts --command ' ' continues to return the child command flags."},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:52:21.279Z"},{"op":"add","path":"/metadata/resolution","value":"Implemented command_namespace recovery for package namespace roots in pm contracts and preserved child command contracts for installed package commands."}],"before_hash":"876076a7415e2f76d6b9f9856ec8d0c970652d0ebc3ac34182306ba0f0e1e7d0","after_hash":"7b58304dbe53bc5f47281f914e84f29426b0ca705f1ed599c81519d04f80bd01","message":"Record contracts namespace resolution metadata"} +{"ts":"2026-06-25T11:52:27.222Z","author":"codex-20260625","op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:52:27.222Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/close_reason","value":"Resolved: contracts now emits command_namespace guidance for package namespace roots and child command contracts remain valid; focused tests, contracts check, full coverage, static quality, and release gates passed."}],"before_hash":"7b58304dbe53bc5f47281f914e84f29426b0ca705f1ed599c81519d04f80bd01","after_hash":"2a3152c28e0b711de9d7b62d446f8d6785b397ae272a7c0c13d3279288d4bc7d"} +{"ts":"2026-06-25T11:52:31.581Z","author":"codex-20260625","op":"release","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:52:31.581Z"}],"before_hash":"2a3152c28e0b711de9d7b62d446f8d6785b397ae272a7c0c13d3279288d4bc7d","after_hash":"a28ff73f3039f0d19ef85eaf068952310aef298fedadd1281cccc1ccf8b5dd1a"} +{"ts":"2026-06-25T11:53:31.416Z","author":"codex-20260625","op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:53:31.416Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"CHANGELOG.md","scope":"project","note":"generated by pm-changelog after closing namespace contracts item"}]}],"before_hash":"a28ff73f3039f0d19ef85eaf068952310aef298fedadd1281cccc1ccf8b5dd1a","after_hash":"f3130679d6b52446391b89ff6ff00b7e91816cae8942ddf7a3055f778e8009cf"} +{"ts":"2026-06-25T11:53:43.587Z","author":"codex-20260625","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-06-25T11:53:43.587Z","author":"codex-20260625","text":"Evidence: refreshed CHANGELOG.md through pm-changelog 2026.6.20 after closure; pnpm changelog:pm:check now passes with item_count=1340 and changed=false."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T11:53:43.587Z"}],"before_hash":"f3130679d6b52446391b89ff6ff00b7e91816cae8942ddf7a3055f778e8009cf","after_hash":"59b2a99248dff840604548935cc6a0adc09d638e45dcf4a2c0538e8d8732973a"} +{"ts":"2026-06-25T12:05:19.486Z","author":"codex-20260625","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-06-25T12:05:19.486Z","author":"codex-20260625","text":"Review response: split the package namespace-root regression into its own dedicated test case after Gemini feedback. Verification: node scripts/run-tests.mjs test -- tests/unit/commands/contracts-command.spec.ts passed 37 tests."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T12:05:19.486Z"}],"before_hash":"59b2a99248dff840604548935cc6a0adc09d638e45dcf4a2c0538e8d8732973a","after_hash":"280ada09ff765c54fb10ff790af7f290140b20b12e6dfde2e6b3687f0f4d49eb"} +{"ts":"2026-06-25T13:16:42.478Z","author":"codex-gpt5","op":"update","patch":[{"op":"remove","path":"/metadata/close_reason"},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:16:42.478Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"280ada09ff765c54fb10ff790af7f290140b20b12e6dfde2e6b3687f0f4d49eb","after_hash":"10d720a850c0d7ad16bb6c076db8acb850239d2bf5438052e48be93b112f014c","message":"Reopen for PR #366 review follow-up: cap contracts namespace suggestions and fallback candidates to preserve token-efficient error payloads."} +{"ts":"2026-06-25T13:16:42.767Z","author":"codex-gpt5","op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:16:42.767Z"},{"op":"add","path":"/metadata/assignee","value":"codex-gpt5"}],"before_hash":"10d720a850c0d7ad16bb6c076db8acb850239d2bf5438052e48be93b112f014c","after_hash":"59aa034ddeff9c28d1e1c7eb6ee7f6e96e07d12db2b6d8da326bbf5319d276de"} +{"ts":"2026-06-25T13:23:05.504Z","author":"codex-gpt5","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-06-25T13:23:05.504Z","author":"codex-gpt5","text":"Review response: capped command namespace recovery output after Gemini feedback. Namespace-root errors now display at most 10 child commands in the message and return at most 20 fallback candidates, while still preserving the first concrete retry and examples. Verification passed: node scripts/run-tests.mjs test -- tests/unit/commands/contracts-command.spec.ts (38 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5098 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, pm health summary ok, git diff --check clean."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:23:05.504Z"}],"before_hash":"59aa034ddeff9c28d1e1c7eb6ee7f6e96e07d12db2b6d8da326bbf5319d276de","after_hash":"f773032e49afca23f6fabff77d331a22b9d73aa574ded87b89d31488260964ec"} +{"ts":"2026-06-25T13:23:05.998Z","author":"codex-gpt5","op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:23:05.998Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/close_reason","value":"Closed after PR #366 review follow-up: contracts namespace guidance is now token-efficient for large extension command groups, with bounded displayed children and fallback candidates plus regression coverage and full gates."}],"before_hash":"f773032e49afca23f6fabff77d331a22b9d73aa574ded87b89d31488260964ec","after_hash":"a0f525084d72eddeaef31a5f68bef163da4e5c5c4e7d41e241ef4c188db561e5"} +{"ts":"2026-06-25T13:23:06.409Z","author":"codex-gpt5","op":"release","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-25T13:23:06.409Z"}],"before_hash":"a0f525084d72eddeaef31a5f68bef163da4e5c5c4e7d41e241ef4c188db561e5","after_hash":"3e2f5d026d35bd0cf55d1b733dac143c76afcadb0bef0b13a7bfdb9523705bb2"} diff --git a/.agents/pm/issues/pm-9gxi.toon b/.agents/pm/issues/pm-9gxi.toon new file mode 100644 index 000000000..ddb8aed75 --- /dev/null +++ b/.agents/pm/issues/pm-9gxi.toon @@ -0,0 +1,45 @@ +id: pm-9gxi +title: "Auto Release blocked: bot cannot push version commit to protected main (GH006, 12 required checks)" +description: "The daily Auto Release (.github/workflows/auto-release.yml -> scripts/release/run-release-pipeline.mjs) failed on 2026-06-25 (run 28151547639). ALL gates passed (250 test files, Sentry/telemetry reliability gate green, static/docs/compat) — the failure is the final step pushReleaseRefs: 'git push --atomic origin HEAD v2026.6.25' is rejected with 'remote: error: GH006: Protected branch update failed for refs/heads/main'. The pipeline creates a version-bump commit (git add package.json CHANGELOG.md + commit, run-release-pipeline.mjs:395) and pushes that fresh commit to main. main's branch protection requires 12 status checks (Build foundation, Runtime smoke x3, Gates x5, Windows regression (Node 24), Docs and Skills, Analyze) and enforce_admins=false. The github-actions bot using GITHUB_TOKEN is NOT an admin, so its direct push of an unchecked commit is rejected; an admin push (owner) bypasses (enforce_admins=false), which is why manual pushes succeed. This worked through 2026-06-24 and regressed 2026-06-25, consistent with required checks being added/enforced on main (the Windows regression check is recent). Net effect: npm is stuck at 2026.6.24 while version:next=2026.6.25; releasable changes (incl. the GH-363 Windows fix in #365) are not being published. Secondary: the 'Auto Release blocked' alert's gh issue create failed that run with 'Resource not accessible by integration (createIssue)' ONLY because pm-qawd/#364 (issues:write) merged at 08:40Z, after the 06:32Z run — issues:write is now on main so the alert will fire on the next scheduled run. REMEDIATION OPTIONS (owner decision; requires a secret or a security-posture change): (1) RECOMMENDED — add a fine-grained PAT secret (e.g. RELEASE_PAT) from an admin with contents:write, and have the auto-release checkout use token: ${{ secrets.RELEASE_PAT || github.token }} so the version-commit push bypasses required checks like an admin; no-regression fallback to GITHUB_TOKEN when unset. (2) Migrate main to a repository ruleset with a bypass actor for the release workflow/bot. (3) Stop committing to main during release — derive the version from the calendar tag only and push just the tag (tags are not branch-protected), moving CHANGELOG regeneration to the existing chore-commit flow. Until resolved, releases can be cut manually by an admin running release:pipeline locally." +type: Issue +status: blocked +priority: 1 +tags[5]: "area:ci",auto-release,branch-protection,release,reliability +created_at: "2026-06-25T11:02:40.952Z" +updated_at: "2026-06-25T13:35:48.242Z" +assignee: codex-gpt5 +author: claude-code-agent +parent: pm-u9d0 +expected_result: "Auto Release production runs use a configured maintainer RELEASE_PAT to push the checked version commit and tag to protected main after gates pass, and missing release credentials fail fast with clear recovery guidance." +actual_result: "Workflow code now validates production push runs before expensive release gates, does not persist elevated checkout credentials, passes RELEASE_PUSH_TOKEN only into run-release-pipeline, deletes it from child process inheritance, and injects git push auth through a per-push extraheader; docs capture the setup requirement. The current release environment still lacks RELEASE_PAT, so scheduled release remains blocked on external secret configuration." +dependencies[3]{id,kind,created_at,author,source_kind}: + pm-7zs0,related,"2026-06-25T11:02:54.128Z",null,null + pm-nb08,related,"2026-06-25T11:02:54.430Z",null,null + pm-y1o4,related,"2026-06-25T11:23:26.383Z",null,null +comments[6]{created_at,author,text}: + "2026-06-25T11:53:04.258Z",codex-20260625,"Evidence: implemented RELEASE_PAT checkout token fallback, production push preflight, and blocked-release alert guidance; documented release environment setup. Verification passed: focused workflow tests (21 tests), full run-gates with telemetry-mode off (build/typecheck/docs/static/coverage/version/secret-scan/npx/package dogfood/npm pack/compat/Sentry all ok), live Sentry/telemetry gate best-effort (Sentry critical=0 high=0, telemetry finish_error_rate_pct=0.78, missing error-code rows=0), pnpm audit low clean, pnpm security:scan clean, no open GitHub PRs/issues/Dependabot/secret alerts. Manual temp smoke passed in /tmp/pm-cli-manual-smoke-NS6WJB with create/claim/update/files/docs/tests/comment/list/validate/health/close/release under sandboxed PM_PATH and PM_GLOBAL_PATH. Remaining external setup: release environment currently has NPM_TOKEN, SENTRY_AUTH_TOKEN, and SENTRY_PERSONAL_ADMIN_TOKEN, but no RELEASE_PAT; scheduled Auto Release will now fail fast until that maintainer token is configured." + "2026-06-25T12:24:45.475Z",codex-20260625,"Review response: addressed CodeRabbit security finding by setting checkout persist-credentials=false, passing RELEASE_PUSH_TOKEN only to run-release-pipeline, deleting it from process.env before child gates run, and injecting a Git extraheader only for git push. Addressed Gemini maintainability feedback by removing the duplicate auto-release workflow assertion block from release-automation-contract.spec.ts and keeping the comprehensive CI workflow contract as the single workflow surface check. Verification: focused review-response tests passed 90 tests; run-release-pipeline unit test passed 33 tests; full coverage passed 100/100/100/100 (5097 tests)." + "2026-06-25T12:38:47.894Z",codex-gpt5,"Review response follow-up: accepted Gemini compatibility feedback and standardized the temporary git push auth extraheader to 'Authorization: Basic' while preserving per-push RELEASE_PUSH_TOKEN scoping and checkout persist-credentials=false. Verification passed after the patch: node scripts/run-tests.mjs test -- tests/unit/scripts/release/run-release-pipeline.spec.ts (33 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5097 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, changelog --check unchanged, pm health summary ok, git diff --check clean." + "2026-06-25T12:55:03.184Z",codex-gpt5,"Review response follow-up: accepted Gemini feedback to append RELEASE_PUSH_TOKEN's git extraheader after any existing GIT_CONFIG_* env entries instead of hardcoding slot 0. Added unit coverage for empty, malformed, and pre-existing Git config env cases. Verification passed: node scripts/run-tests.mjs test -- tests/unit/scripts/release/run-release-pipeline.spec.ts (33 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5097 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, changelog --check unchanged, pm health summary ok, git diff --check clean." + "2026-06-25T13:08:46.131Z",codex-gpt5,"Review response follow-up: accepted CodeRabbit finding and aligned the Auto Release workflow preflight with run-release-pipeline's trimmed RELEASE_PUSH_TOKEN behavior. Push-mode releases now fail fast when RELEASE_PAT is absent or when the effective RELEASE_PUSH_TOKEN is whitespace-only, before expensive release work and before a late git push failure. Added ci-workflow contract coverage for the trimmed token guard. Verification passed: focused workflow/release tests (40 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5097 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, changelog --check unchanged, pm health summary ok, git diff --check clean." + "2026-06-25T13:35:48.242Z",codex-gpt5,"Review response follow-up: accepted Gemini defensive-programming feedback for withReleasePushCredentials by normalizing explicit null gitOptions before reading env, while preserving existing env merge and RELEASE_PUSH_TOKEN push-only scoping. Added unit coverage for null gitOptions. Verification passed: node scripts/run-tests.mjs test -- tests/unit/scripts/release/run-release-pipeline.spec.ts (33 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5098 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, git diff --check clean." +files[7]{path,scope,note}: + .github/workflows/auto-release.yml,project,wire RELEASE_PAT checkout token and push preflight + package.json,project,refresh @sentry/node dependency for release reliability + pnpm-lock.yaml,project,lock @sentry/node 10.61.0 dependency graph + scripts/release/run-release-pipeline.mjs,project,scope RELEASE_PUSH_TOKEN to git push only + tests/integration/ci-workflow-contract.spec.ts,project,assert auto-release workflow token and alert contract + tests/integration/release-automation-contract.spec.ts,project,assert auto-release RELEASE_PAT contract + tests/unit/scripts/release/run-release-pipeline.spec.ts,project,cover release push token scoping +tests[6]{command,path,scope,timeout_seconds,pm_context_mode,env_set,env_clear,shared_host_safe,assert_stdout_contains,assert_stdout_regex,assert_stderr_contains,assert_stderr_regex,assert_stdout_min_lines,assert_json_field_equals,assert_json_field_gte,note}: + node scripts/release/run-gates.mjs --json --telemetry-mode off,null,project,900,null,null,null,null,null,null,null,null,null,null,null,null + node scripts/release/sentry-telemetry-gate.mjs --json --telemetry-mode best-effort,null,project,180,null,null,null,null,null,null,null,null,null,null,null,null + node scripts/run-tests.mjs test -- tests/integration/release-automation-contract.spec.ts tests/integration/ci-workflow-contract.spec.ts,null,project,240,null,null,null,null,null,null,null,null,null,null,null,null + node scripts/run-tests.mjs test -- tests/unit/scripts/release/run-release-pipeline.spec.ts tests/integration/ci-workflow-contract.spec.ts tests/integration/release-automation-contract.spec.ts tests/unit/commands/contracts-command.spec.ts,null,project,240,null,null,null,null,null,null,null,null,null,null,null,null + pnpm audit --audit-level low,null,project,120,null,null,null,null,null,null,null,null,null,null,null,null + "pnpm security:scan",null,project,120,null,null,null,null,null,null,null,null,null,null,null,null +test_runs[1]{run_id,kind,status,started_at,finished_at,recorded_at,attempt,resumed_from,passed,failed,skipped,items,linked_tests,fail_on_skipped_triggered}: + test-local-mqtf2n44-55ns6h,test,passed,"2026-06-25T11:26:22.261Z","2026-06-25T11:26:27.461Z","2026-06-25T11:26:27.461Z",null,null,1,0,0,null,null,null +docs[1]{path,scope,note}: + docs/RELEASING.md,project,document release push token setup and fail-fast policy +body: "" diff --git a/.agents/pm/issues/pm-y1o4.toon b/.agents/pm/issues/pm-y1o4.toon index 10f4cd34a..82ae6e3e8 100644 --- a/.agents/pm/issues/pm-y1o4.toon +++ b/.agents/pm/issues/pm-y1o4.toon @@ -2,18 +2,34 @@ id: pm-y1o4 title: Contracts command lookup should handle package namespace roots description: The 2026-06-25 source-map audit found that an installed package namespace can expose help at the root command path while pm contracts --command reports unknown_command; child command lookup works. type: Issue -status: open +status: closed priority: 2 tags[4]: agent-ux,"area:contracts","area:mcp","area:packages" created_at: "2026-06-25T04:53:47.719Z" -updated_at: "2026-06-25T04:53:47.719Z" +updated_at: "2026-06-25T13:23:06.409Z" author: codex-pm-ecosystem-audit-20260625 estimated_minutes: 120 acceptance_criteria: "The intended contract behavior for package namespace roots is defined; pm contracts either returns namespace metadata/child-command guidance for roots like changelog or emits a clearer package-namespace error; regression coverage exercises installed package namespace root and child command; pnpm contracts:check and package command discovery tests pass." parent: pm-5k4v repro_steps: "Run node dist/cli.js changelog --help, then node dist/cli.js contracts --command changelog --flags-only --json and node dist/cli.js contracts --command \"changelog generate\" --flags-only --json." -expected_result: "Contracts lookup gives useful namespace-level metadata or a precise guidance error for the package namespace root, while child command lookup remains valid." -actual_result: "Root namespace help exists, but contracts --command changelog returns unknown_command; contracts --command \"changelog generate\" works." -comments[1]{created_at,author,text}: +resolution: Implemented command_namespace recovery for package namespace roots in pm contracts and preserved child command contracts for installed package commands. +expected_result: "pm contracts --command gives precise child-command guidance instead of unknown_command, while pm contracts --command ' ' continues to return the child command flags." +actual_result: pm contracts --command changelog now reports command_namespace with concrete changelog export/generate retry examples; changelog generate/export child lookups return extension-provided flag contracts. +comments[5]{created_at,author,text}: "2026-06-25T04:53:47.719Z",codex-pm-ecosystem-audit-20260625,"Duplicate check before create: status-all search for contracts --command changelog unknown_command package root command full path changelog generate found related closed items pm-7etc, pm-4os2/pm-d6kq class work, and pm-zqes class work, but no open direct namespace-root contracts item." + "2026-06-25T11:52:14.770Z",codex-20260625,"Evidence: implemented command_namespace guidance for package namespace roots in contracts lookup; added regression coverage for changelog namespace roots and child commands. Verification passed: node scripts/run-tests.mjs test -- tests/unit/commands/contracts-command.spec.ts (36 tests), pnpm contracts:check, node scripts/run-tests.mjs coverage (100/100/100/100), static-quality gate docstrings 237/237 source and 1840/1840 exported." + "2026-06-25T11:53:43.587Z",codex-20260625,"Evidence: refreshed CHANGELOG.md through pm-changelog 2026.6.20 after closure; pnpm changelog:pm:check now passes with item_count=1340 and changed=false." + "2026-06-25T12:05:19.486Z",codex-20260625,"Review response: split the package namespace-root regression into its own dedicated test case after Gemini feedback. Verification: node scripts/run-tests.mjs test -- tests/unit/commands/contracts-command.spec.ts passed 37 tests." + "2026-06-25T13:23:05.504Z",codex-gpt5,"Review response: capped command namespace recovery output after Gemini feedback. Namespace-root errors now display at most 10 child commands in the message and return at most 20 fallback candidates, while still preserving the first concrete retry and examples. Verification passed: node scripts/run-tests.mjs test -- tests/unit/commands/contracts-command.spec.ts (38 tests), node scripts/run-tests.mjs coverage (100/100/100/100; 5098 tests), node scripts/release/static-quality-gate.mjs --json (source docstrings 237/237 and exported docstrings 1840/1840), pnpm contracts:check, pm health summary ok, git diff --check clean." +files[2]{path,scope,note}: + src/cli/commands/contracts.ts,project,emit command_namespace guidance for package command roots + tests/unit/commands/contracts-command.spec.ts,project,regress namespace root and child command contract behavior +tests[2]{command,path,scope,timeout_seconds,pm_context_mode,env_set,env_clear,shared_host_safe,assert_stdout_contains,assert_stdout_regex,assert_stderr_contains,assert_stderr_regex,assert_stdout_min_lines,assert_json_field_equals,assert_json_field_gte,note}: + node scripts/run-tests.mjs test -- tests/unit/commands/contracts-command.spec.ts,null,project,240,null,null,null,null,null,null,null,null,null,null,null,null + "pnpm contracts:check",null,project,240,null,null,null,null,null,null,null,null,null,null,null,null +test_runs[1]{run_id,kind,status,started_at,finished_at,recorded_at,attempt,resumed_from,passed,failed,skipped,items,linked_tests,fail_on_skipped_triggered}: + test-local-mqtf2w7w-ehc5qs,test,passed,"2026-06-25T11:26:32.946Z","2026-06-25T11:26:39.260Z","2026-06-25T11:26:39.260Z",null,null,1,0,0,null,null,null +docs[1]{path,scope,note}: + CHANGELOG.md,project,generated by pm-changelog after closing namespace contracts item +close_reason: "Closed after PR #366 review follow-up: contracts namespace guidance is now token-efficient for large extension command groups, with bounded displayed children and fallback candidates plus regression coverage and full gates." body: "" diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index 58e53c344..54302b1fc 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -55,6 +55,10 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + # Do not persist the elevated release token through checkout or + # dependency installation. run-release-pipeline scopes RELEASE_PAT to + # the git push process only. + persist-credentials: false - name: Setup pnpm uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6 @@ -106,6 +110,8 @@ jobs: INPUT_PUSH: ${{ github.event_name == 'workflow_dispatch' && (inputs.push && 'true' || 'false') || 'true' }} INPUT_DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && (inputs.dry_run && 'true' || 'false') || 'false' }} INPUT_TELEMETRY_MODE: ${{ github.event_name == 'workflow_dispatch' && inputs.telemetry_mode || 'off' }} + RELEASE_PAT_CONFIGURED: ${{ secrets.RELEASE_PAT != '' }} + RELEASE_PUSH_TOKEN: ${{ secrets.RELEASE_PAT || github.token }} GH_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_PERSONAL_ADMIN_TOKEN: ${{ secrets.SENTRY_PERSONAL_ADMIN_TOKEN }} @@ -115,6 +121,11 @@ jobs: echo "dry_run=true cannot be combined with push=true" exit 2 fi + if [[ "${INPUT_PUSH}" == "true" && "${INPUT_DRY_RUN}" != "true" && ( "${RELEASE_PAT_CONFIGURED}" != "true" || -z "${RELEASE_PUSH_TOKEN//[[:space:]]/}" ) ]]; then + echo "RELEASE_PAT is required before Auto Release can push the checked version commit/tag to protected main." + echo "Create a release environment secret from a maintainer token with contents:write and branch-protection bypass rights." + exit 1 + fi if [[ "${INPUT_PUSH}" == "true" && "${INPUT_DRY_RUN}" != "true" && -z "${SENTRY_PERSONAL_ADMIN_TOKEN:-}" ]]; then echo "SENTRY_PERSONAL_ADMIN_TOKEN is required before Auto Release can create a version commit/tag." echo "The downstream Release workflow treats the Sentry reliability gate as mandatory; failing here prevents unpublished tags." @@ -172,7 +183,11 @@ jobs: Run: ${RUN_URL} Commit: ${RELEASE_SHA} - A common cause is the Sentry/telemetry reliability gate blocking on an unresolved fatal/error issue inside its recent-activity window (\`--sentry-window-days\`). Resolve the issue in Sentry (or inspect the gate's \`blocking_short_ids\`), then re-run Auto Release. This issue is auto-updated so blocked daily releases are never silently skipped." + Common causes: + - \`RELEASE_PAT\` is missing from the release environment, so Auto Release cannot push its checked version commit/tag to protected \`main\`. + - The Sentry/telemetry reliability gate blocked on an unresolved fatal/error issue inside its recent-activity window (\`--sentry-window-days\`). + + Configure the release push token or resolve the gate's \`blocking_short_ids\`, then re-run Auto Release. This issue is auto-updated so blocked daily releases are never silently skipped." if [[ -n "${existing_issue}" ]]; then gh issue comment "${existing_issue}" --body "${body}" diff --git a/CHANGELOG.md b/CHANGELOG.md index bd23ddf53..35e8c6a91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ ### Fixed +- Contracts command lookup should handle package namespace roots ([pm-y1o4](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-y1o4.toon)) - GH-363: Windows nightly (Node 24) red — runtime-loader colon-path + telemetry detached-spawn unhandled error + npm-install regression ([pm-xaib](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-xaib.toon)) - Auto Release blocked-alert step can never create its tracking issue (auto-release.yml missing issues:write) ([pm-qawd](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-qawd.toon)) - Sentry PM-CLI-1T: pm stats should tolerate disappearing history streams ([pm-7o0s](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-7o0s.toon)) diff --git a/docs/RELEASING.md b/docs/RELEASING.md index b40b91bb0..c5eabb32a 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -36,6 +36,7 @@ pnpm version:check ## One-Time Setup - Use npm provenance publishing for `.github/workflows/release.yml` so GitHub-hosted release jobs publish signed packages. Keep `id-token: write`, Node 24 or newer, npm 11.5.1 or newer, `NODE_AUTH_TOKEN` from the `release` environment `NPM_TOKEN` secret, and `npm publish --access public --provenance`. The token must authenticate as a maintainer with read-write access to `@unbrained/pm-cli`. +- Add `RELEASE_PAT` to the `release` environment from a maintainer token with `contents:write` and branch-protection bypass rights. Auto Release creates a checked version/changelog commit and tag on `main`; the default `GITHUB_TOKEN` has `contents:write` but cannot satisfy protected-branch required status checks for that freshly-created commit. The workflow does not persist this elevated token during checkout or dependency installation; `run-release-pipeline.mjs` scopes it to the git push process. - Add `SENTRY_AUTH_TOKEN` as an optional GitHub Environment or repository secret when Sentry release creation and sourcemap upload should run. Add `SENTRY_PERSONAL_ADMIN_TOKEN` for the GitHub-hosted Sentry issue-threshold gate; CI-scoped release tokens may not have issue-read scope. The release workflow skips Sentry upload cleanly when `SENTRY_AUTH_TOKEN` is absent, but fails the reliability threshold gate when `SENTRY_PERSONAL_ADMIN_TOKEN` is absent; local maintainers should still run the token-backed Sentry gate before release. - Keep any `release` environment compatible with free GitHub features. This repository is public, so environment secrets and tag/branch deployment rules are compatible with the free GitHub path; do not add paid-only release gates. - Ensure `GITHUB_TOKEN` has `contents: write` for GitHub Release creation. @@ -54,6 +55,7 @@ Policy: - same-day follow-up release (`YYYY.M.D-N`) is manual-only via `allow_same_day_release=true` - release preparation must pass all quality and compatibility gates before commit+tag push - `CHANGELOG.md` is generated by the latest npm `pm-changelog` package (`pm install npm:pm-changelog --project`, then `pm changelog generate --mode replace --all-release-tags`) from closed tracker items across git release tag windows and checked in CI; do not edit it by hand +- protected-branch pushes require `RELEASE_PAT`; Auto Release fails fast before the expensive release gates when `push=true`, `dry_run=false`, and that secret is not configured - release reliability gating requires `SENTRY_PERSONAL_ADMIN_TOKEN` for issue-threshold checks; Auto Release fails before creating the version commit/tag when the token is missing and `push=true`, while sourcemap upload remains optional through `SENTRY_AUTH_TOKEN` - after creating and pushing a new tag, auto-release dispatches `.github/workflows/release.yml` with that tag and waits for the publish workflow to finish, because GitHub does not start normal push/tag workflows from `GITHUB_TOKEN` pushes diff --git a/package.json b/package.json index 28c5e3d1a..c4f6afcb5 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ } }, "dependencies": { - "@sentry/node": "^10.60.0", + "@sentry/node": "^10.61.0", "@toon-format/toon": "^2.3.0", "commander": "^15.0.0", "fast-glob": "^3.3.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55632acca..063ee4cf1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,8 +17,8 @@ importers: .: dependencies: '@sentry/node': - specifier: ^10.60.0 - version: 10.60.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1)) + specifier: ^10.61.0 + version: 10.61.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1)) '@toon-format/toon': specifier: ^2.3.0 version: 2.3.0 @@ -305,141 +305,141 @@ packages: resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} engines: {node: '>=14'} - '@rollup/rollup-android-arm-eabi@4.62.1': - resolution: {integrity: sha512-WUtumI+yIc7YXY3ZtN68V50CHEjgopo0rIZ90+ZqlZzIGroVn3qkfK7wkdl+HebaxenGQMrlB/KJs+aLMZg9lQ==} + '@rollup/rollup-android-arm-eabi@4.62.2': + resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.62.1': - resolution: {integrity: sha512-ivTbxKROae184UB9SNQGOmXCwdgq1rb1OfDOXHOw9bHHVtoUSQoyLwAgxcd9zlef+vtPnyqN22HrYvaI7K12Zw==} + '@rollup/rollup-android-arm64@4.62.2': + resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.62.1': - resolution: {integrity: sha512-+nRm4AIocYcaE5yP07KGybXGDGfBCXOSY7EE7GeGvA8rzK+eiZteAgn9VNkn8sw/+FWR+9FLyph0gUNuY75KuQ==} + '@rollup/rollup-darwin-arm64@4.62.2': + resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.62.1': - resolution: {integrity: sha512-63zVs6JwE9i3BMhHm1Gi5+LP8dRKQVrD5UzgjDgZfptON38vfStA4iAK0DpxqTmI8udUzr1Qwk1tEhLRcj7PVA==} + '@rollup/rollup-darwin-x64@4.62.2': + resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.62.1': - resolution: {integrity: sha512-uXASB7+/ZbR7q4RC35T/xTwQt4Qwt8e1my8E7hI6PxaQxuNiuvM+B/I58xvJLaVYOmCGy9cu3Ky1SSY4ia/G0Q==} + '@rollup/rollup-freebsd-arm64@4.62.2': + resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.62.1': - resolution: {integrity: sha512-BqeibWSAOg/6bwxDnJ1Z4806jc6kIuGYCDS52DY4u23EgcK3DMrm4rrODmPTltA8EFlvhz2gXGhs/RwgWuto/w==} + '@rollup/rollup-freebsd-x64@4.62.2': + resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.62.1': - resolution: {integrity: sha512-9ryebRuEJ1OcKl9ZWWyXZ84OrpqXl8qwa99ZwrVn1uzBu9TwNqpyoScK7yF/+WoHW0dBGUR3tAHem7nWP1ismQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': + resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.62.1': - resolution: {integrity: sha512-HOHv0qumBDTLxM/j5nE2X6SVHGK2F5r211WqFn0PB+lJL3o4HBP9CsjlcdwIk6aILYeRveltSVmvv9NSW3vnWg==} + '@rollup/rollup-linux-arm-musleabihf@4.62.2': + resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.62.1': - resolution: {integrity: sha512-jrDLxV5iWL8fdpj5N5+9ZAd2BjD3U6h1eiVhOCDQhvKG+C0uJt3phgIsS7sWKTk4LLaom87dMJCIXnakXEs4fA==} + '@rollup/rollup-linux-arm64-gnu@4.62.2': + resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.62.1': - resolution: {integrity: sha512-kaKe83aR+a5bvGTdXFlUzGUFPHoSm2zo1PFalUuwqj7+txbLm4jyXwM4IkmrEWK9yAWE9qO654XuBb8dqgSP4A==} + '@rollup/rollup-linux-arm64-musl@4.62.2': + resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.62.1': - resolution: {integrity: sha512-tp+VgVhkZ9iNDGezXQnBx0h+ZraZJCKtbrsxGRSO3Y+Ta/YrUfLxlKXU4IiBm9AWlj9EDH1Djrvsl6ledeUdJg==} + '@rollup/rollup-linux-loong64-gnu@4.62.2': + resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.62.1': - resolution: {integrity: sha512-LN9invzRf8ejduiGlrtr46Gk08Uh/1eiMMLgo/CNPHeRpYH8EYW6YQuAqkoxItk+Rtmod1raQ8W49sO+hP+6hQ==} + '@rollup/rollup-linux-loong64-musl@4.62.2': + resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.62.1': - resolution: {integrity: sha512-F2Abce1ndQR8UXEX8Bj3EFd5jlw/u0rlbjmsEzBPty/YJ8H57x3POPnBxr7Mbi8m7UNwukwFW6Z20I+hrQvWdQ==} + '@rollup/rollup-linux-ppc64-gnu@4.62.2': + resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.62.1': - resolution: {integrity: sha512-nmJq25UletS/fI3icrKsBH8KDkTf7cSGTY5bkWI9z3+4oHj1DxHQkWCP8uP7m+AEhc1fc73AcycZam4iViAoNQ==} + '@rollup/rollup-linux-ppc64-musl@4.62.2': + resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.62.1': - resolution: {integrity: sha512-HqWXZHGXFrKmSs3qOmNBfLY34CzYDt3HU2oQq2cplmU1gEADa2dWf6xcjrQuHYbNYZpJY2+rLNAbHyXtrO/0PQ==} + '@rollup/rollup-linux-riscv64-gnu@4.62.2': + resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.62.1': - resolution: {integrity: sha512-xYDVRyJEbrzr14Z2hqe59C1pwosdl9Td0ik5gu5x85mVswTweg492as4Vzs/8zKkvvUgO5VdGRL7OzN+W9Z6+w==} + '@rollup/rollup-linux-riscv64-musl@4.62.2': + resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.62.1': - resolution: {integrity: sha512-X6n4yZUYAGSZTsIRjHUFkRZy/ml+EyS5vsgnyUOfhflKros0TEjX9yAoFqiRdJSfmykStVUyfcFDy/tHJ64JuQ==} + '@rollup/rollup-linux-s390x-gnu@4.62.2': + resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.62.1': - resolution: {integrity: sha512-nVQGk/jStQc2V4rrkI+vPD2J+85boKqS4R4nOdPhc3eWw0kyW/b+AYRGoH8qo057XSVqaTx13AliH5qPeLTtgQ==} + '@rollup/rollup-linux-x64-gnu@4.62.2': + resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.62.1': - resolution: {integrity: sha512-Ae54IyMwpY3JsYjBH4k29vQ9FSoILwJdh7j7c9lmLOczKnU/WL5jMRL9epsgPrs+ph48YVTsy6PkQDq0nK8Kvg==} + '@rollup/rollup-linux-x64-musl@4.62.2': + resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.62.1': - resolution: {integrity: sha512-7oOS0UqUXLRi2dVeEXdQxbml854xxQSx+6Pdnuo4G0iAIRiPBCIyzhLIv8oSmvqLkAftGaRk+ft70fVHXjsXsQ==} + '@rollup/rollup-openbsd-x64@4.62.2': + resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.62.1': - resolution: {integrity: sha512-e6kAhhmUK3pwICnBtsQFkg/czVxFlY5e4Ppi4fuXWvOwiHOXlgQMEvpg0H5ceuEh2T1nyI0U6SfhV3qojKWpAg==} + '@rollup/rollup-openharmony-arm64@4.62.2': + resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.62.1': - resolution: {integrity: sha512-xXRJSv00uVmj5DwS9DwIvS+Re5VdDnaspDfk7GzsnhP1IbTzFjJwhY+c3j3jr/2pP/prBrXvZ1OmjjhkkAOUlQ==} + '@rollup/rollup-win32-arm64-msvc@4.62.2': + resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.62.1': - resolution: {integrity: sha512-D3S8+6cSEW0QZZHcKKDQ/Fsz/eqvYmJbtkZZziFxEb4Fi4fyWTCaMs1p5siQ85/T6gNdYKJ3OIJ4M/phYQgICA==} + '@rollup/rollup-win32-ia32-msvc@4.62.2': + resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.62.1': - resolution: {integrity: sha512-CRVGPQKdEB/ujGfrq3SgITWc2N9iWM+sqaBKHh62Dc6xRLQGTVrqHpOVEitfly941kr244j14sswRw47bmMjjg==} + '@rollup/rollup-win32-x64-gnu@4.62.2': + resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.62.1': - resolution: {integrity: sha512-/N8QHE1y6A9nmN3HCIFZWr5FUu/rKcT/A7JgaMJH3dcvL5RS++o0brK5SitYVTis/dJFiasK7Xva0cqeWYmCzQ==} + '@rollup/rollup-win32-x64-msvc@4.62.2': + resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} cpu: [x64] os: [win32] @@ -499,12 +499,12 @@ packages: resolution: {integrity: sha512-z1JQrl/1SLY+8wpzvork6vl+fpsg/oCCxM7HWWhUnI/R+OGNyoIzieQuggX3uUMY7NBtp8UWCQx6FeFazzOF9g==} engines: {node: '>=14'} - '@sentry/core@10.60.0': - resolution: {integrity: sha512-szN7ccOJAEaLb1BBQzCQhABGMTJmKNUk0G2sc7rWhajeXoZoMKIbNkI9RvJrFuV69cbad/d/BKGBjbpJhySAzw==} + '@sentry/core@10.61.0': + resolution: {integrity: sha512-Edg8t2w45qEKiFnjeA6zRmU47R6la5FEMG+maZEOB2oTyJ+ujmh8LGaZ3G8aC0VdkKn8CXhHtDesze6oDc1oTA==} engines: {node: '>=18'} - '@sentry/node-core@10.60.0': - resolution: {integrity: sha512-aXi9ixvP+hgUZPPZCRwMNHgY2I0gkSeoAKAUuysDJhWDmrygwfGdlkbGmmtW6PQjtMYFx69Igt5btvhjEBoJTw==} + '@sentry/node-core@10.61.0': + resolution: {integrity: sha512-aVSnYqaq5FXv9hX6lVGbg4gB+mVrb6QDoNE/IBq8OBR90TR9I/KU6KlWAcfB9H7I6CHnedldOpljkMAJ5eZ3qA==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -524,20 +524,20 @@ packages: '@opentelemetry/sdk-trace-base': optional: true - '@sentry/node@10.60.0': - resolution: {integrity: sha512-u//paUrkKaCr0oNn7r7UulGydkYMSkU1wQOIpG/P/jf7psZWnyXhgeszHzUfZXo6pCdxXG9z9viPvzGjqPQN7A==} + '@sentry/node@10.61.0': + resolution: {integrity: sha512-nct3VqOIuPBnsvqHHWkPG6Ta7QwJftxWXQzHt0+soNcWBoh5WU8hEzIPVEXzxTThJ9AOkF/df3ApWUX4i6ylqQ==} engines: {node: '>=18'} - '@sentry/opentelemetry@10.60.0': - resolution: {integrity: sha512-gl+2NVH+9RmTu7pd9kV1tKif+Th+p9tmnXR1l3Sb3Wqo1ir5FaNMKrloWEKMXjnepii9EJUrEHdSC+i8NoexxQ==} + '@sentry/opentelemetry@10.61.0': + resolution: {integrity: sha512-wg8bY1sWPyFOVh59ThiFDeuyheD7DdQliqWmrCCa5q+PSRLij+zpmsGqjlzGU74lzj1Kvpkicw5LsO6U49b2xA==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 '@opentelemetry/core': '>=2.8.0' '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@sentry/server-utils@10.60.0': - resolution: {integrity: sha512-SX+MzWM3nz5ttKT48rlfktm0ERyIpDLma+b6pYeWgW2oFHKcpIu0g0qMGJrZs4lKM3MlgV7IqLa4texMqTp9kQ==} + '@sentry/server-utils@10.61.0': + resolution: {integrity: sha512-IrOyMzlOyBkWtnVYb54sALf2f8WVqyyp7woRfHw8c3IMwUr5AskGOi7k2rjmUXO3Q0UkfHNVarexiEfo8ZqTsg==} engines: {node: '>=18'} '@standard-schema/spec@1.1.0': @@ -706,8 +706,8 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - import-in-the-middle@3.1.0: - resolution: {integrity: sha512-c0AeAV8VcwZzfYE7euTZY3H+VXUPMVugiovdosq80lqEXJmOekg3zGUAYg6KImHMaMuBoTUfTv7xNpUFdy0hJA==} + import-in-the-middle@3.2.0: + resolution: {integrity: sha512-vR2B6HKIhaBjcZr2bLpFiJ1VbzOlRQ7aby4/gw5WPIzToLjqpfWw3VJ4sk1uDchoOODEirvO2jyrSPtUSL5CrQ==} engines: {node: '>=18'} is-extglob@2.1.1: @@ -772,8 +772,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.13: - resolution: {integrity: sha512-sPdqC6ByMVVGvF1ynvvMo0/o+oD1VX7DaHhijt1bFgjvBkHBib4t49GoNDhf2NDta4oeUNlaGbSt5K7qjZ955Q==} + nanoid@3.3.15: + resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -817,8 +817,8 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rollup@4.62.1: - resolution: {integrity: sha512-XTvxjHHM/0J/WZBg+ehDbAZgIpZoIZtWO+aImyuhjoyQa56NBX/bqnXw32rT27fkjSRrqthOgkLjRVtwXFI7jQ==} + rollup@4.62.2: + resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -1144,7 +1144,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/api-logs': 0.214.0 - import-in-the-middle: 3.1.0 + import-in-the-middle: 3.2.0 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color @@ -1164,79 +1164,79 @@ snapshots: '@opentelemetry/semantic-conventions@1.41.1': {} - '@rollup/rollup-android-arm-eabi@4.62.1': + '@rollup/rollup-android-arm-eabi@4.62.2': optional: true - '@rollup/rollup-android-arm64@4.62.1': + '@rollup/rollup-android-arm64@4.62.2': optional: true - '@rollup/rollup-darwin-arm64@4.62.1': + '@rollup/rollup-darwin-arm64@4.62.2': optional: true - '@rollup/rollup-darwin-x64@4.62.1': + '@rollup/rollup-darwin-x64@4.62.2': optional: true - '@rollup/rollup-freebsd-arm64@4.62.1': + '@rollup/rollup-freebsd-arm64@4.62.2': optional: true - '@rollup/rollup-freebsd-x64@4.62.1': + '@rollup/rollup-freebsd-x64@4.62.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.62.1': + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.62.1': + '@rollup/rollup-linux-arm-musleabihf@4.62.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.62.1': + '@rollup/rollup-linux-arm64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.62.1': + '@rollup/rollup-linux-arm64-musl@4.62.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.62.1': + '@rollup/rollup-linux-loong64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-loong64-musl@4.62.1': + '@rollup/rollup-linux-loong64-musl@4.62.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.62.1': + '@rollup/rollup-linux-ppc64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-ppc64-musl@4.62.1': + '@rollup/rollup-linux-ppc64-musl@4.62.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.62.1': + '@rollup/rollup-linux-riscv64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-riscv64-musl@4.62.1': + '@rollup/rollup-linux-riscv64-musl@4.62.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.62.1': + '@rollup/rollup-linux-s390x-gnu@4.62.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.62.1': + '@rollup/rollup-linux-x64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-x64-musl@4.62.1': + '@rollup/rollup-linux-x64-musl@4.62.2': optional: true - '@rollup/rollup-openbsd-x64@4.62.1': + '@rollup/rollup-openbsd-x64@4.62.2': optional: true - '@rollup/rollup-openharmony-arm64@4.62.1': + '@rollup/rollup-openharmony-arm64@4.62.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.62.1': + '@rollup/rollup-win32-arm64-msvc@4.62.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.62.1': + '@rollup/rollup-win32-ia32-msvc@4.62.2': optional: true - '@rollup/rollup-win32-x64-gnu@4.62.1': + '@rollup/rollup-win32-x64-gnu@4.62.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.62.1': + '@rollup/rollup-win32-x64-msvc@4.62.2': optional: true '@sentry/cli-darwin@3.5.1': @@ -1281,51 +1281,51 @@ snapshots: '@sentry/conventions@0.12.0': {} - '@sentry/core@10.60.0': {} + '@sentry/core@10.61.0': {} - '@sentry/node-core@10.60.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))': + '@sentry/node-core@10.61.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))': dependencies: '@sentry/conventions': 0.12.0 - '@sentry/core': 10.60.0 - '@sentry/opentelemetry': 10.60.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) - import-in-the-middle: 3.1.0 + '@sentry/core': 10.61.0 + '@sentry/opentelemetry': 10.61.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) + import-in-the-middle: 3.2.0 optionalDependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) - '@sentry/node@10.60.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))': + '@sentry/node@10.61.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.41.1 - '@sentry/core': 10.60.0 - '@sentry/node-core': 10.60.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) - '@sentry/opentelemetry': 10.60.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) - '@sentry/server-utils': 10.60.0 - import-in-the-middle: 3.1.0 + '@sentry/core': 10.61.0 + '@sentry/node-core': 10.61.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) + '@sentry/opentelemetry': 10.61.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) + '@sentry/server-utils': 10.61.0 + import-in-the-middle: 3.2.0 transitivePeerDependencies: - '@opentelemetry/core' - '@opentelemetry/exporter-trace-otlp-http' - supports-color - '@sentry/opentelemetry@10.60.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))': + '@sentry/opentelemetry@10.61.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) '@sentry/conventions': 0.12.0 - '@sentry/core': 10.60.0 + '@sentry/core': 10.61.0 - '@sentry/server-utils@10.60.0': + '@sentry/server-utils@10.61.0': dependencies: '@apm-js-collab/code-transformer': 0.15.0 '@apm-js-collab/code-transformer-bundler-plugins': 0.5.0 '@apm-js-collab/tracing-hooks': 0.10.0 '@sentry/conventions': 0.12.0 - '@sentry/core': 10.60.0 + '@sentry/core': 10.61.0 magic-string: 0.30.21 transitivePeerDependencies: - supports-color @@ -1510,7 +1510,7 @@ snapshots: html-escaper@2.0.2: {} - import-in-the-middle@3.1.0: + import-in-the-middle@3.2.0: dependencies: acorn: 8.17.0 acorn-import-attributes: 1.9.5(acorn@8.17.0) @@ -1572,7 +1572,7 @@ snapshots: ms@2.1.3: {} - nanoid@3.3.13: {} + nanoid@3.3.15: {} obug@2.1.3: {} @@ -1586,7 +1586,7 @@ snapshots: postcss@8.5.15: dependencies: - nanoid: 3.3.13 + nanoid: 3.3.15 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -1605,35 +1605,35 @@ snapshots: reusify@1.1.0: {} - rollup@4.62.1: + rollup@4.62.2: dependencies: '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.62.1 - '@rollup/rollup-android-arm64': 4.62.1 - '@rollup/rollup-darwin-arm64': 4.62.1 - '@rollup/rollup-darwin-x64': 4.62.1 - '@rollup/rollup-freebsd-arm64': 4.62.1 - '@rollup/rollup-freebsd-x64': 4.62.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.1 - '@rollup/rollup-linux-arm-musleabihf': 4.62.1 - '@rollup/rollup-linux-arm64-gnu': 4.62.1 - '@rollup/rollup-linux-arm64-musl': 4.62.1 - '@rollup/rollup-linux-loong64-gnu': 4.62.1 - '@rollup/rollup-linux-loong64-musl': 4.62.1 - '@rollup/rollup-linux-ppc64-gnu': 4.62.1 - '@rollup/rollup-linux-ppc64-musl': 4.62.1 - '@rollup/rollup-linux-riscv64-gnu': 4.62.1 - '@rollup/rollup-linux-riscv64-musl': 4.62.1 - '@rollup/rollup-linux-s390x-gnu': 4.62.1 - '@rollup/rollup-linux-x64-gnu': 4.62.1 - '@rollup/rollup-linux-x64-musl': 4.62.1 - '@rollup/rollup-openbsd-x64': 4.62.1 - '@rollup/rollup-openharmony-arm64': 4.62.1 - '@rollup/rollup-win32-arm64-msvc': 4.62.1 - '@rollup/rollup-win32-ia32-msvc': 4.62.1 - '@rollup/rollup-win32-x64-gnu': 4.62.1 - '@rollup/rollup-win32-x64-msvc': 4.62.1 + '@rollup/rollup-android-arm-eabi': 4.62.2 + '@rollup/rollup-android-arm64': 4.62.2 + '@rollup/rollup-darwin-arm64': 4.62.2 + '@rollup/rollup-darwin-x64': 4.62.2 + '@rollup/rollup-freebsd-arm64': 4.62.2 + '@rollup/rollup-freebsd-x64': 4.62.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 + '@rollup/rollup-linux-arm-musleabihf': 4.62.2 + '@rollup/rollup-linux-arm64-gnu': 4.62.2 + '@rollup/rollup-linux-arm64-musl': 4.62.2 + '@rollup/rollup-linux-loong64-gnu': 4.62.2 + '@rollup/rollup-linux-loong64-musl': 4.62.2 + '@rollup/rollup-linux-ppc64-gnu': 4.62.2 + '@rollup/rollup-linux-ppc64-musl': 4.62.2 + '@rollup/rollup-linux-riscv64-gnu': 4.62.2 + '@rollup/rollup-linux-riscv64-musl': 4.62.2 + '@rollup/rollup-linux-s390x-gnu': 4.62.2 + '@rollup/rollup-linux-x64-gnu': 4.62.2 + '@rollup/rollup-linux-x64-musl': 4.62.2 + '@rollup/rollup-openbsd-x64': 4.62.2 + '@rollup/rollup-openharmony-arm64': 4.62.2 + '@rollup/rollup-win32-arm64-msvc': 4.62.2 + '@rollup/rollup-win32-ia32-msvc': 4.62.2 + '@rollup/rollup-win32-x64-gnu': 4.62.2 + '@rollup/rollup-win32-x64-msvc': 4.62.2 fsevents: 2.3.3 run-parallel@1.2.0: @@ -1693,7 +1693,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.15 - rollup: 4.62.1 + rollup: 4.62.2 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 22.20.0 diff --git a/scripts/release/run-release-pipeline.mjs b/scripts/release/run-release-pipeline.mjs index 999e59363..98402cf8f 100644 --- a/scripts/release/run-release-pipeline.mjs +++ b/scripts/release/run-release-pipeline.mjs @@ -1,5 +1,6 @@ #!/usr/bin/env node +import { Buffer } from "node:buffer"; import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { mkdirSync } from "node:fs"; import { tmpdir } from "node:os"; @@ -17,6 +18,9 @@ import { } from "./utils.mjs"; import { isReleaseRelevantPath } from "./release-relevance.mjs"; +const releasePushToken = process.env.RELEASE_PUSH_TOKEN?.trim() ?? ""; +delete process.env.RELEASE_PUSH_TOKEN; + export function usage() { console.log(`Usage: node scripts/release/run-release-pipeline.mjs [--json] @@ -182,7 +186,8 @@ function isBranchBehindPushFailure(result) { } export function pushReleaseRefs(tagName, gitOptions = {}) { - const firstPush = git(["push", "--atomic", "origin", "HEAD", tagName], { ...gitOptions, allowFailure: true }); + const pushGitOptions = withReleasePushCredentials(gitOptions); + const firstPush = git(["push", "--atomic", "origin", "HEAD", tagName], { ...pushGitOptions, allowFailure: true }); if (firstPush.status === 0) { return { retried: false }; } @@ -200,7 +205,7 @@ export function pushReleaseRefs(tagName, gitOptions = {}) { fail(`Command failed: git rebase origin/main\n${detail}`); } git(["tag", "-f", tagName, "HEAD"], gitOptions); - const retryPush = git(["push", "--atomic", "origin", "HEAD", tagName], { ...gitOptions, allowFailure: true }); + const retryPush = git(["push", "--atomic", "origin", "HEAD", tagName], { ...pushGitOptions, allowFailure: true }); if (retryPush.status !== 0) { const detail = `${retryPush.stderr.trim()}\n${retryPush.stdout.trim()}`.trim(); fail(`Command failed: git push --atomic origin HEAD ${tagName}\n${detail}`); @@ -208,6 +213,28 @@ export function pushReleaseRefs(tagName, gitOptions = {}) { return { retried: true }; } +export function withReleasePushCredentials(gitOptions = {}, token = releasePushToken) { + const options = gitOptions ?? {}; + if (!token) { + return options; + } + const baseEnv = options.env ?? {}; + const existingGitConfigCount = Number.parseInt(baseEnv.GIT_CONFIG_COUNT ?? "0", 10); + const gitConfigIndex = Number.isInteger(existingGitConfigCount) && existingGitConfigCount >= 0 + ? existingGitConfigCount + : 0; + const authHeader = `Authorization: Basic ${Buffer.from(`x-access-token:${token}`, "utf8").toString("base64")}`; + return { + ...options, + env: { + ...baseEnv, + GIT_CONFIG_COUNT: String(gitConfigIndex + 1), + [`GIT_CONFIG_KEY_${gitConfigIndex}`]: "http.https://github.com/.extraheader", + [`GIT_CONFIG_VALUE_${gitConfigIndex}`]: authHeader, + }, + }; +} + export function runPipeline() { const { flags } = parseFlags(process.argv.slice(2)); if (flags.get("help") || flags.get("h")) { diff --git a/src/cli/commands/contracts.ts b/src/cli/commands/contracts.ts index 498ffac6a..55d36bbdb 100644 --- a/src/cli/commands/contracts.ts +++ b/src/cli/commands/contracts.ts @@ -385,6 +385,9 @@ const COMMAND_ALIAS_TO_CANONICAL = new Map( ), ); +const COMMAND_NAMESPACE_DISPLAY_LIMIT = 10; +const COMMAND_NAMESPACE_FALLBACK_LIMIT = 20; + // Lifecycle subcommand flag contracts for `pm extension`. Only `init` differs // between extension and package: `pm package init` / `pm packages init` // additionally accept the package-only `--declarative` flag, so the package @@ -1638,6 +1641,43 @@ export async function runContracts( .sort((left, right) => left.localeCompare(right)); const commandNames = new Set(commandCatalog); if (selectedCommand && !commandNames.has(selectedCommand)) { + const namespaceChildren = commandCatalog.filter((command) => + command.startsWith(`${selectedCommand} `), + ); + if (namespaceChildren.length > 0) { + const displayedNamespaceChildren = namespaceChildren.slice(0, COMMAND_NAMESPACE_DISPLAY_LIMIT); + const hiddenNamespaceChildCount = namespaceChildren.length - displayedNamespaceChildren.length; + const displayedChildCommandList = hiddenNamespaceChildCount > 0 + ? `${displayedNamespaceChildren.join(", ")}, and ${hiddenNamespaceChildCount} more` + : displayedNamespaceChildren.join(", "); + const fallbackCandidates = namespaceChildren.slice(0, COMMAND_NAMESPACE_FALLBACK_LIMIT); + const childCommandExamples = namespaceChildren + .slice(0, 5) + .map((command) => `pm contracts --command "${command}" --flags-only --json`); + const suggestedChildCommand = namespaceChildren[0]; + throw new PmCliError( + `Command "${options.command}" is a command namespace. Choose a concrete child command: ${displayedChildCommandList}.`, + EXIT_CODE.USAGE, + { + code: "command_namespace", + required: "Use a concrete child command path listed under this namespace.", + why: + "Command groups expose help at the namespace root, but command flag contracts belong to executable child commands.", + examples: childCommandExamples, + nextSteps: [ + `Retry with a child command, for example: ${childCommandExamples[0]}`, + ], + recovery: { + suggested_retry: `pm contracts --command "${suggestedChildCommand}" --flags-only --json`, + fallback_candidates: fallbackCandidates.map((command) => ({ + source: "command_namespace", + command: `pm contracts --command "${command}" --flags-only --json`, + reason: `Child command under ${selectedCommand}`, + })), + }, + }, + ); + } const packageHint = PACKAGE_OWNED_COMMAND_INSTALL_HINTS.get(selectedCommand); if (packageHint) { throw new PmCliError( diff --git a/tests/integration/ci-workflow-contract.spec.ts b/tests/integration/ci-workflow-contract.spec.ts index 183cc887f..292da883f 100644 --- a/tests/integration/ci-workflow-contract.spec.ts +++ b/tests/integration/ci-workflow-contract.spec.ts @@ -334,9 +334,11 @@ describe("GitHub workflow contract", () => { "permissions:", "actions: write", "contents: write", + "issues: write", "concurrency:", "cancel-in-progress: false", PINNED_ACTIONS.checkout, + "persist-credentials: false", PINNED_ACTIONS.pnpmSetup, PINNED_ACTIONS.setupNode, "name: Restore TypeScript and Vitest caches", @@ -351,6 +353,10 @@ describe("GitHub workflow contract", () => { "--allow-same-day-release", "--dry-run", "--push", + "RELEASE_PAT_CONFIGURED: ${{ secrets.RELEASE_PAT != '' }}", + "RELEASE_PUSH_TOKEN: ${{ secrets.RELEASE_PAT || github.token }}", + '-z "${RELEASE_PUSH_TOKEN//[[:space:]]/}"', + "RELEASE_PAT is required before Auto Release can push", "node scripts/release/run-release-pipeline.mjs", "--telemetry-mode", "gh workflow run release.yml --ref main -f tag=\"${NEW_TAG}\"", @@ -360,10 +366,12 @@ describe("GitHub workflow contract", () => { "GH_TOKEN: ${{ github.token }}", "RELEASE_SHA: ${{ github.sha }}", "Auto Release blocked: scheduled run failed", + "Common causes:", 'gh issue list --state open --search "\\"${title}\\" in:title"', "gh issue create --title", "gh issue comment", ]); + expect(autoReleaseWorkflow).not.toContain("token: ${{ secrets.RELEASE_PAT || github.token }}"); }); it("keeps CodeQL actions SHA-pinned for supply-chain safety (pm-ji5c)", async () => { diff --git a/tests/integration/release-automation-contract.spec.ts b/tests/integration/release-automation-contract.spec.ts index fef309332..2ae6b122c 100644 --- a/tests/integration/release-automation-contract.spec.ts +++ b/tests/integration/release-automation-contract.spec.ts @@ -50,28 +50,6 @@ describe("release automation contract", () => { expect(packageJson.scripts?.["changelog:pm:check"]).toContain("--check"); }); - it("keeps auto-release workflow aligned with one-per-day and manual override controls", async () => { - const workflow = await readFile(path.join(repoRoot, ".github/workflows/auto-release.yml"), "utf8"); - expect(workflow).toContain("schedule:"); - expect(workflow).toContain("workflow_dispatch:"); - expect(workflow).toContain("allow_same_day_release:"); - expect(workflow).toContain("dry_run:"); - expect(workflow).toContain("push:"); - expect(workflow).toContain('default: "off"'); - expect(workflow).toContain('- "off"'); - expect(workflow).toContain("--allow-same-day-release"); - expect(workflow).toContain("--dry-run"); - expect(workflow).toContain("--push"); - expect(workflow).toContain("node scripts/release/run-release-pipeline.mjs"); - expect(workflow).toContain("actions: write"); - // The blocked-release alert opens/updates a tracking issue, which needs issues:write. - expect(workflow).toContain("issues: write"); - expect(workflow).toContain("gh workflow run release.yml --ref main -f tag=\"${NEW_TAG}\""); - expect(workflow).toContain("gh run watch \"${RELEASE_RUN_ID}\" --compact --exit-status --interval 30"); - expect(workflow).toContain("SENTRY_AUTH_TOKEN"); - expect(workflow).toContain("SENTRY_PERSONAL_ADMIN_TOKEN"); - }); - it("keeps bundle rebuilds safe for concurrent local pm invocations", async () => { const bundleScript = await readFile(path.join(repoRoot, "scripts/bundle-cli.mjs"), "utf8"); expect(bundleScript).not.toContain("rm(outputDir"); diff --git a/tests/unit/commands/contracts-command.spec.ts b/tests/unit/commands/contracts-command.spec.ts index 50fbe3c2e..6c9590054 100644 --- a/tests/unit/commands/contracts-command.spec.ts +++ b/tests/unit/commands/contracts-command.spec.ts @@ -1870,6 +1870,149 @@ describe("contracts command runtime", () => { }); }); + it("rejects command namespace roots and suggests concrete child commands", async () => { + await withTempPmPath(async (context) => { + await writeTestExtension({ + root: context.pmPath, + placement: "projectRoot", + directory: "changelog-namespace-contracts", + manifest: { + name: "changelog-namespace-contracts", + version: "1.0.0", + entry: "./index.mjs", + capabilities: ["commands", "schema"], + }, + entryFilename: "index.mjs", + entrySource: [ + "export default {", + " activate(api) {", + " api.registerCommand({", + " name: 'changelog generate',", + " action: 'changelog-generate',", + " flags: [{ long: '--output', value_name: 'file', value_type: 'string' }],", + " run: () => ({ ok: true }),", + " });", + " api.registerCommand({", + " name: 'changelog export',", + " action: 'changelog-export',", + " flags: [{ long: '--format', value_name: 'format', value_type: 'string' }],", + " run: () => ({ ok: true }),", + " });", + " },", + "};", + "", + ].join("\n"), + }); + + await expect( + runContracts( + { command: "changelog", flagsOnly: true }, + { ...GLOBAL_OPTIONS, path: context.pmPath }, + ), + ).rejects.toMatchObject({ + message: + 'Command "changelog" is a command namespace. Choose a concrete child command: changelog export, changelog generate.', + exitCode: EXIT_CODE.USAGE, + context: expect.objectContaining({ + code: "command_namespace", + required: "Use a concrete child command path listed under this namespace.", + why: expect.stringContaining("command flag contracts belong to executable child commands"), + examples: expect.arrayContaining([ + 'pm contracts --command "changelog export" --flags-only --json', + 'pm contracts --command "changelog generate" --flags-only --json', + ]), + recovery: expect.objectContaining({ + suggested_retry: 'pm contracts --command "changelog export" --flags-only --json', + fallback_candidates: expect.arrayContaining([ + { + source: "command_namespace", + command: 'pm contracts --command "changelog generate" --flags-only --json', + reason: "Child command under changelog", + }, + ]), + }), + }), + }); + + const childResult = await runContracts( + { command: "changelog generate", flagsOnly: true }, + { ...GLOBAL_OPTIONS, path: context.pmPath }, + ); + expect(childResult.command_flags).toEqual([ + expect.objectContaining({ + command: "changelog generate", + provider: "extension", + flags: [expect.objectContaining({ flag: "--output" })], + }), + ]); + }); + }); + + it("caps command namespace suggestions for large extension command groups", async () => { + await withTempPmPath(async (context) => { + const commandRegistrations = Array.from({ length: 25 }, (_entry, index) => { + const suffix = String(index).padStart(2, "0"); + return [ + " api.registerCommand({", + ` name: 'bulk action-${suffix}',`, + ` action: 'bulk-action-${suffix}',`, + " flags: [{ long: '--target', value_name: 'id', value_type: 'string' }],", + " run: () => ({ ok: true }),", + " });", + ].join("\n"); + }); + await writeTestExtension({ + root: context.pmPath, + placement: "projectRoot", + directory: "bulk-namespace-contracts", + manifest: { + name: "bulk-namespace-contracts", + version: "1.0.0", + entry: "./index.mjs", + capabilities: ["commands", "schema"], + }, + entryFilename: "index.mjs", + entrySource: [ + "export default {", + " activate(api) {", + ...commandRegistrations, + " },", + "};", + "", + ].join("\n"), + }); + + let thrown: unknown; + try { + await runContracts( + { command: "bulk", flagsOnly: true }, + { ...GLOBAL_OPTIONS, path: context.pmPath }, + ); + } catch (error: unknown) { + thrown = error; + } + + expect(thrown).toBeInstanceOf(PmCliError); + const error = thrown as PmCliError; + const errorContext = error.context as { + recovery?: { + fallback_candidates?: Array<{ command: string }>; + }; + }; + expect(error.message).toContain("bulk action-00"); + expect(error.message).toContain("bulk action-09"); + expect(error.message).toContain("and 15 more"); + expect(error.message).not.toContain("bulk action-10"); + expect(errorContext.recovery?.fallback_candidates).toHaveLength(20); + expect(errorContext.recovery?.fallback_candidates?.at(0)?.command).toBe( + 'pm contracts --command "bulk action-00" --flags-only --json', + ); + expect(errorContext.recovery?.fallback_candidates?.at(-1)?.command).toBe( + 'pm contracts --command "bulk action-19" --flags-only --json', + ); + }); + }); + it("rejects unknown action and command filters", async () => { await expect( runContracts({ action: "unknown-action" }, GLOBAL_OPTIONS), diff --git a/tests/unit/scripts/release/run-release-pipeline.spec.ts b/tests/unit/scripts/release/run-release-pipeline.spec.ts index 302d58627..f35b41f80 100644 --- a/tests/unit/scripts/release/run-release-pipeline.spec.ts +++ b/tests/unit/scripts/release/run-release-pipeline.spec.ts @@ -1,3 +1,4 @@ +import { Buffer } from "node:buffer"; import path from "node:path"; import { describe, expect, it, vi } from "vitest"; import { createScriptHarness } from "../../../helpers/scriptModule"; @@ -27,6 +28,10 @@ type PipelineModule = { skipCompatibility: boolean; skipTelemetrySentry: boolean; }) => { ok: boolean; telemetry_mode: string }; + withReleasePushCredentials: ( + options?: { env?: Record } | null, + token?: string, + ) => { env?: Record }; pushReleaseRefs: (tagName: string, options?: { env?: Record }) => { retried: boolean }; runPipeline: () => void; }; @@ -465,6 +470,79 @@ describe("run-release-pipeline", () => { ); }); + it("scopes RELEASE_PUSH_TOKEN to git push without leaving it in child environments", async () => { + process.env.RELEASE_PUSH_TOKEN = "release-token"; + const runCommand = vi.fn(() => ({ status: 0, stdout: "", stderr: "" })); + mockUtils(runCommand); + + const mod = await harness.importModuleStable(SCRIPT); + expect(process.env.RELEASE_PUSH_TOKEN).toBeUndefined(); + expect(mod.pushReleaseRefs("v2026.6.18", { env: { GIT_AUTHOR_NAME: "release-bot" } })).toEqual({ + retried: false, + }); + const expectedHeader = `Authorization: Basic ${Buffer.from( + "x-access-token:release-token", + "utf8", + ).toString("base64")}`; + expect(runCommand).toHaveBeenCalledWith( + "git", + ["push", "--atomic", "origin", "HEAD", "v2026.6.18"], + expect.objectContaining({ + allowFailure: true, + env: { + GIT_AUTHOR_NAME: "release-bot", + GIT_CONFIG_COUNT: "1", + GIT_CONFIG_KEY_0: "http.https://github.com/.extraheader", + GIT_CONFIG_VALUE_0: expectedHeader, + }, + }), + ); + expect(mod.withReleasePushCredentials({ env: { GIT_AUTHOR_NAME: "release-bot" } }, "")).toEqual({ + env: { GIT_AUTHOR_NAME: "release-bot" }, + }); + expect(mod.withReleasePushCredentials({}, "release-token")).toEqual({ + env: { + GIT_CONFIG_COUNT: "1", + GIT_CONFIG_KEY_0: "http.https://github.com/.extraheader", + GIT_CONFIG_VALUE_0: expectedHeader, + }, + }); + expect(mod.withReleasePushCredentials(null, "release-token")).toEqual({ + env: { + GIT_CONFIG_COUNT: "1", + GIT_CONFIG_KEY_0: "http.https://github.com/.extraheader", + GIT_CONFIG_VALUE_0: expectedHeader, + }, + }); + expect(mod.withReleasePushCredentials({ env: { GIT_CONFIG_COUNT: "not-a-number" } }, "release-token")).toEqual({ + env: { + GIT_CONFIG_COUNT: "1", + GIT_CONFIG_KEY_0: "http.https://github.com/.extraheader", + GIT_CONFIG_VALUE_0: expectedHeader, + }, + }); + expect( + mod.withReleasePushCredentials( + { + env: { + GIT_CONFIG_COUNT: "1", + GIT_CONFIG_KEY_0: "safe.directory", + GIT_CONFIG_VALUE_0: "/workspace/pm-cli", + }, + }, + "release-token", + ), + ).toEqual({ + env: { + GIT_CONFIG_COUNT: "2", + GIT_CONFIG_KEY_0: "safe.directory", + GIT_CONFIG_VALUE_0: "/workspace/pm-cli", + GIT_CONFIG_KEY_1: "http.https://github.com/.extraheader", + GIT_CONFIG_VALUE_1: expectedHeader, + }, + }); + }); + it("aborts and fails when release push rebase cannot replay cleanly", async () => { const gitCalls: string[][] = []; const runCommand = vi.fn((command: string, args: string[]) => {