Skip to content

fix(keys-sync): use datetime.UTC in the near-expiry test (ruff UP017) - #1646

Merged
potiuk merged 1 commit into
apache:mainfrom
potiuk:fix-ruff-up017
Oct 16, 2026
Merged

potiuk merged 1 commit into
apache:mainfrom
potiuk:fix-ruff-up017

Conversation

@potiuk

@potiuk potiuk commented Oct 16, 2026

Copy link
Copy Markdown
Member

Summary

Test plan

  • ruff check passes on plugins/magpie-release-management
  • keys-sync unit tests pass

Generated-by: GitHub Copilot (Claude Sonnet 5.5)

Generated-by: GitHub Copilot (Claude Sonnet 5.5)
@github-actions github-actions Bot added capability:resolve Close-out: invalidate, dedupe, CVE allocate, announcement family:release-management release-* skills labels Oct 16, 2026
@potiuk
potiuk merged commit b1f6e34 into apache:main Oct 16, 2026
10 checks passed
potiuk added a commit that referenced this pull request Oct 16, 2026
…er fixes into the tool and read S3 and version paths right

Port of the key-checker fixes main landed on the script this series moves
into tools/release-management (#1634, #1635, #1646):

- A key passes only with a signing-capable primary or subkey that itself
  meets the strength floor and is not revoked, invalid, disabled or
  expired; a certify-only primary with no such subkey is blocked
  (`signers` in the check output).
- GPG failures are reported, never read as "key not found": unreadable or
  non-file input, a failed import or listing, and gpg failing to start are
  errors naming the stage and exit code, with the "no key data" exception
  ported as is. release-verify list-keys, which runs gpg for keys-sync,
  now also reports each key's capabilities and subkeys.
- Every test of main's test_check_key.py has a ported equivalent.

Adversarial-review findings:

- archive-sweep reads S3 URLs with promote's whole-host path-style rule,
  so a virtual-hosted bucket whose name starts with "s3" keeps its key.
- A release_dist_url_template with a literal around <version> (v<version>,
  foo-<version>-bin) gives the right release directory and archive URLs.
- keys-sync reads a GitHub KEYS URL as branch (the first segment after
  blob/) plus a path that may include subdirectories, so KEYS can live
  in e.g. dist/; a new optional keys_file_branch names a branch that
  contains '/' (release/1.x). Without it, a subdirectory reading is
  warned; a URL whose file is not KEYS is refused.
- The keyserver's UIDs are compared with KEYS as a set, so a reordered
  keyserver listing is no longer reported as a rolled key.

Generated-by: Claude Opus 5
potiuk added a commit that referenced this pull request Oct 16, 2026
…er fixes into the tool and read S3 and version paths right

Port of the key-checker fixes main landed on the script this series moves
into tools/release-management (#1634, #1635, #1646):

- A key passes only with a signing-capable primary or subkey that itself
  meets the strength floor and is not revoked, invalid, disabled or
  expired; a certify-only primary with no such subkey is blocked
  (`signers` in the check output).
- GPG failures are reported, never read as "key not found": unreadable or
  non-file input, a failed import or listing, and gpg failing to start are
  errors naming the stage and exit code, with the "no key data" exception
  ported as is. release-verify list-keys, which runs gpg for keys-sync,
  now also reports each key's capabilities and subkeys.
- Every test of main's test_check_key.py has a ported equivalent.

Adversarial-review findings:

- archive-sweep reads S3 URLs with promote's whole-host path-style rule,
  so a virtual-hosted bucket whose name starts with "s3" keeps its key.
- A release_dist_url_template with a literal around <version> (v<version>,
  foo-<version>-bin) gives the right release directory and archive URLs.
- keys-sync reads a GitHub KEYS URL as branch (the first segment after
  blob/) plus a path that may include subdirectories, so KEYS can live
  in e.g. dist/; a new optional keys_file_branch names a branch that
  contains '/' (release/1.x). Without it, a subdirectory reading is
  warned; a URL whose file is not KEYS is refused.
- The keyserver's UIDs are compared with KEYS as a set, so a reordered
  keyserver listing is no longer reported as a rolled key.

Generated-by: Claude Opus 5
potiuk added a commit that referenced this pull request Oct 16, 2026
…er fixes into the tool and read S3 and version paths right

Port of the key-checker fixes main landed on the script this series moves
into tools/release-management (#1634, #1635, #1646):

- A key passes only with a signing-capable primary or subkey that itself
  meets the strength floor and is not revoked, invalid, disabled or
  expired; a certify-only primary with no such subkey is blocked
  (`signers` in the check output).
- GPG failures are reported, never read as "key not found": unreadable or
  non-file input, a failed import or listing, and gpg failing to start are
  errors naming the stage and exit code, with the "no key data" exception
  ported as is. release-verify list-keys, which runs gpg for keys-sync,
  now also reports each key's capabilities and subkeys.
- Every test of main's test_check_key.py has a ported equivalent.

Adversarial-review findings:

- archive-sweep reads S3 URLs with promote's whole-host path-style rule,
  so a virtual-hosted bucket whose name starts with "s3" keeps its key.
- A release_dist_url_template with a literal around <version> (v<version>,
  foo-<version>-bin) gives the right release directory and archive URLs.
- keys-sync reads a GitHub KEYS URL as branch (the first segment after
  blob/) plus a path that may include subdirectories, so KEYS can live
  in e.g. dist/; a new optional keys_file_branch names a branch that
  contains '/' (release/1.x). Without it, a subdirectory reading is
  warned; a URL whose file is not KEYS is refused.
- The keyserver's UIDs are compared with KEYS as a set, so a reordered
  keyserver listing is no longer reported as a rolled key.

Generated-by: Claude Opus 5
potiuk added a commit that referenced this pull request Oct 16, 2026
…er fixes into the tool and read S3 and version paths right

Port of the key-checker fixes main landed on the script this series moves
into tools/release-management (#1634, #1635, #1646):

- A key passes only with a signing-capable primary or subkey that itself
  meets the strength floor and is not revoked, invalid, disabled or
  expired; a certify-only primary with no such subkey is blocked
  (`signers` in the check output).
- GPG failures are reported, never read as "key not found": unreadable or
  non-file input, a failed import or listing, and gpg failing to start are
  errors naming the stage and exit code, with the "no key data" exception
  ported as is. release-verify list-keys, which runs gpg for keys-sync,
  now also reports each key's capabilities and subkeys.
- Every test of main's test_check_key.py has a ported equivalent.

Adversarial-review findings:

- archive-sweep reads S3 URLs with promote's whole-host path-style rule,
  so a virtual-hosted bucket whose name starts with "s3" keeps its key.
- A release_dist_url_template with a literal around <version> (v<version>,
  foo-<version>-bin) gives the right release directory and archive URLs.
- keys-sync reads a GitHub KEYS URL as branch (the first segment after
  blob/) plus a path that may include subdirectories, so KEYS can live
  in e.g. dist/; a new optional keys_file_branch names a branch that
  contains '/' (release/1.x). Without it, a subdirectory reading is
  warned; a URL whose file is not KEYS is refused.
- The keyserver's UIDs are compared with KEYS as a set, so a reordered
  keyserver listing is no longer reported as a rolled key.

Generated-by: Claude Opus 5
potiuk added a commit that referenced this pull request Oct 16, 2026
…er fixes into the tool and read S3 and version paths right

Port of the key-checker fixes main landed on the script this series moves
into tools/release-management (#1634, #1635, #1646):

- A key passes only with a signing-capable primary or subkey that itself
  meets the strength floor and is not revoked, invalid, disabled or
  expired; a certify-only primary with no such subkey is blocked
  (`signers` in the check output).
- GPG failures are reported, never read as "key not found": unreadable or
  non-file input, a failed import or listing, and gpg failing to start are
  errors naming the stage and exit code, with the "no key data" exception
  ported as is. release-verify list-keys, which runs gpg for keys-sync,
  now also reports each key's capabilities and subkeys.
- Every test of main's test_check_key.py has a ported equivalent.

Adversarial-review findings:

- archive-sweep reads S3 URLs with promote's whole-host path-style rule,
  so a virtual-hosted bucket whose name starts with "s3" keeps its key.
- A release_dist_url_template with a literal around <version> (v<version>,
  foo-<version>-bin) gives the right release directory and archive URLs.
- keys-sync reads a GitHub KEYS URL as branch (the first segment after
  blob/) plus a path that may include subdirectories, so KEYS can live
  in e.g. dist/; a new optional keys_file_branch names a branch that
  contains '/' (release/1.x). Without it, a subdirectory reading is
  warned; a URL whose file is not KEYS is refused.
- The keyserver's UIDs are compared with KEYS as a set, so a reordered
  keyserver listing is no longer reported as a rolled key.

Generated-by: Claude Opus 5
potiuk added a commit that referenced this pull request Oct 16, 2026
…er fixes into the tool and read S3 and version paths right

Port of the key-checker fixes main landed on the script this series moves
into tools/release-management (#1634, #1635, #1646):

- A key passes only with a signing-capable primary or subkey that itself
  meets the strength floor and is not revoked, invalid, disabled or
  expired; a certify-only primary with no such subkey is blocked
  (`signers` in the check output).
- GPG failures are reported, never read as "key not found": unreadable or
  non-file input, a failed import or listing, and gpg failing to start are
  errors naming the stage and exit code, with the "no key data" exception
  ported as is. release-verify list-keys, which runs gpg for keys-sync,
  now also reports each key's capabilities and subkeys.
- Every test of main's test_check_key.py has a ported equivalent.

Adversarial-review findings:

- archive-sweep reads S3 URLs with promote's whole-host path-style rule,
  so a virtual-hosted bucket whose name starts with "s3" keeps its key.
- A release_dist_url_template with a literal around <version> (v<version>,
  foo-<version>-bin) gives the right release directory and archive URLs.
- keys-sync reads a GitHub KEYS URL as branch (the first segment after
  blob/) plus a path that may include subdirectories, so KEYS can live
  in e.g. dist/; a new optional keys_file_branch names a branch that
  contains '/' (release/1.x). Without it, a subdirectory reading is
  warned; a URL whose file is not KEYS is refused.
- The keyserver's UIDs are compared with KEYS as a set, so a reordered
  keyserver listing is no longer reported as a rolled key.

Generated-by: Claude Opus 5
potiuk added a commit that referenced this pull request Oct 16, 2026
…er fixes into the tool and read S3 and version paths right

Port of the key-checker fixes main landed on the script this series moves
into tools/release-management (#1634, #1635, #1646):

- A key passes only with a signing-capable primary or subkey that itself
  meets the strength floor and is not revoked, invalid, disabled or
  expired; a certify-only primary with no such subkey is blocked
  (`signers` in the check output).
- GPG failures are reported, never read as "key not found": unreadable or
  non-file input, a failed import or listing, and gpg failing to start are
  errors naming the stage and exit code, with the "no key data" exception
  ported as is. release-verify list-keys, which runs gpg for keys-sync,
  now also reports each key's capabilities and subkeys.
- Every test of main's test_check_key.py has a ported equivalent.

Adversarial-review findings:

- archive-sweep reads S3 URLs with promote's whole-host path-style rule,
  so a virtual-hosted bucket whose name starts with "s3" keeps its key.
- A release_dist_url_template with a literal around <version> (v<version>,
  foo-<version>-bin) gives the right release directory and archive URLs.
- keys-sync reads a GitHub KEYS URL as branch (the first segment after
  blob/) plus a path that may include subdirectories, so KEYS can live
  in e.g. dist/; a new optional keys_file_branch names a branch that
  contains '/' (release/1.x). Without it, a subdirectory reading is
  warned; a URL whose file is not KEYS is refused.
- The keyserver's UIDs are compared with KEYS as a set, so a reordered
  keyserver listing is no longer reported as a rolled key.

Generated-by: Claude Opus 5
potiuk added a commit that referenced this pull request Oct 16, 2026
… decide and render as code (#1625)

* perf(release-audit-report, release-archive-sweep, release-keys-sync): decide and render as code

The last three release skills each had one rule in a skill-local script
and the rest in prose. The scripts move unchanged into
tools/release-management (render_record → audit_report.record,
retention → archive_sweep, check_key → keys_sync), and new commands do
what the agent did by hand, printing JSON and running nothing:

- audit-report: `verdict` (planning issue found, `org/repo#n`
  normalised to the canonical URL), `gather` (PonyMail subjects and
  queries, the `svn info` revision command, the required fields; the
  search itself stays with the agent), `voters` (the [RESULT] voters
  mapped to roster handles with vote-tally's binding resolution,
  unresolved ones listed, never cited), `check` (Step 1 missing /
  redacted fields, schema violations, the thread-permalink shape),
  `record`, and `pr`.
- archive-sweep: `verdict`, `listing`, `trains` (strict `N.x` lines
  become patterns; a free-text retention rule leaves `keep` to the
  agent), `retention`, and `render` for svn mv, gh release delete (with
  the permanent-deletion warning), aws s3 mv, self-hosted, and atr
  (no command).
- keys-sync: whether the fingerprint is in KEYS and its UID matches the
  keyserver's is no longer a text scan. A new read-only
  `release-verify list-keys` lists fingerprints and UIDs in the
  existing throwaway GNUPGHOME (no agent, no keyring, no network,
  private-key material refused), and `keys-sync verdict` classifies it
  as proceed / noop / blocked, failing closed when it cannot compare.
  `render` draws the `# <uid>` KEYS block, the svn / git / generic
  sequence and the upload reminder with the expiry advisory.

Every rendered command quotes its values with the shared shell helpers.
Each backend and outcome gets its own file; audit-report's PR step
moves, byte-identical with its generated adversarial block, to
audit-log-pr.md at the skill root. Golden rules, Hard rules and the
eval headings are unchanged. audit-report 6,657 → 5,136 tokens,
archive-sweep 4,573 → 4,165, keys-sync 4,871 → 4,584.

Evals: the scripted cases become pytest cases named after each former
case (expected records byte-identical); the judgement and injection
cases stay, their fixtures now carrying the real tool output.

Generated-by: Claude Opus 5
Claude-Session: https://claude.ai/code/session_01GTPsZ5aEE5bUVYqp47Dpvv

* fix(release-archive-sweep, release-keys-sync, release-audit-report): refuse what the rules forbid instead of defaulting

Review findings on the three tools:

- archive-sweep: `retention` refuses a trains file whose retention rule
  was not decided (keep_decided false) unless every train names its keep,
  so a free-text rule no longer falls back to keep=1 and archives what
  the rule keeps.
- archive-sweep: `render` refuses a retention output without
  mapping_complete, and any latest-of-line, orphan or pre-release in
  past_retention (Golden rule 2).
- archive-sweep: a trailing -incubating qualifier is a release, not a
  pre-release, so podlings archive their older releases.
- keys-sync: the Step 0 verdict normalises the fingerprint as Step 1
  does (a 0x prefix no longer turns the no-op into a duplicate append).
- keys-sync: Step 2 requires --key-listing and appends only an armour
  holding exactly the key Step 1 checked.
- audit-report: `pr --base` defaults to <default-branch>, not main.

Generated-by: Claude Opus 5

* fix(release-keys-sync, release-archive-sweep): carry main's key-checker fixes into the tool and read S3 and version paths right

Port of the key-checker fixes main landed on the script this series moves
into tools/release-management (#1634, #1635, #1646):

- A key passes only with a signing-capable primary or subkey that itself
  meets the strength floor and is not revoked, invalid, disabled or
  expired; a certify-only primary with no such subkey is blocked
  (`signers` in the check output).
- GPG failures are reported, never read as "key not found": unreadable or
  non-file input, a failed import or listing, and gpg failing to start are
  errors naming the stage and exit code, with the "no key data" exception
  ported as is. release-verify list-keys, which runs gpg for keys-sync,
  now also reports each key's capabilities and subkeys.
- Every test of main's test_check_key.py has a ported equivalent.

Adversarial-review findings:

- archive-sweep reads S3 URLs with promote's whole-host path-style rule,
  so a virtual-hosted bucket whose name starts with "s3" keeps its key.
- A release_dist_url_template with a literal around <version> (v<version>,
  foo-<version>-bin) gives the right release directory and archive URLs.
- keys-sync reads a GitHub KEYS URL as branch (the first segment after
  blob/) plus a path that may include subdirectories, so KEYS can live
  in e.g. dist/; a new optional keys_file_branch names a branch that
  contains '/' (release/1.x). Without it, a subdirectory reading is
  warned; a URL whose file is not KEYS is refused.
- The keyserver's UIDs are compared with KEYS as a set, so a reordered
  keyserver listing is no longer reported as a rolled key.

Generated-by: Claude Opus 5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capability:resolve Close-out: invalidate, dedupe, CVE allocate, announcement family:release-management release-* skills

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant