Skip to content

ci: bump apm-action pin to v1.10.0 + pack-format drift trap#1907

Merged
danielmeppiel merged 4 commits into
mainfrom
bump-apm-action-v1.10.0
Jun 25, 2026
Merged

ci: bump apm-action pin to v1.10.0 + pack-format drift trap#1907
danielmeppiel merged 4 commits into
mainfrom
bump-apm-action-v1.10.0

Conversation

@danielmeppiel

Copy link
Copy Markdown
Collaborator

TL;DR

Propagates the released apm-action v1.10.0 (.zip bundle detection) into the shared gh-aw workflow and lands a cross-repo drift trap that guards the exact outage shape that motivated it.

Why

apm pack --archive defaults to .zip at apm >= 0.20 (#1720). apm-action @v1.7.2 only detected .tar.gz, so the release GH-AW Compatibility job failed with "apm pack produced no bundle". apm-action v1.10.0 is now released (microsoft/apm-action#52) and adds .zip detection (ARCHIVE_EXTENSIONS = ['.zip', '.tar.gz']); the floating v1 tag has moved, so @v1 consumers are already healed. This PR brings the pinned shared workflow up to the same release and prevents silent re-drift.

What changed

shared/apm.md

  • Pin microsoft/apm-action@v1.7.2 -> @v1.10.0 (5 references).
  • apm-version schema default: '0.12.4' -> '0.14.0' in lockstep. Job Set C requires the schema default to mirror the pinned action's apm-version default, and v1.10.0 ships 0.14.0. Side effect: non-opting gh-aw consumers now default to apm CLI 0.14.0 (already every other consumer's effective default — a staleness catch-up, the pin was 2 releases behind).

3 apm-action consumer locks (docs-sync, pr-review-panel, triage-panel), recompiled on gh-aw v0.80.9:

  • apm-action@d723bb64 # v1.10.0 and apm-version 0.14.0 at all call sites; actions-lock.json re-keyed to the v1.10.0 SHA. No compiler/firewall churn — the diff is pin/version-scoped only (5 files + the trap).

verify-shared-apm-matrix.yml — new Job Set D (pack-format consumer compat)

  • Cross-references the producer default archive format in src/apm_cli/bundle/packer.py (.zip) against the archive-extension set the pinned apm-action release detects (src/bundler.ts). Fails on the "apm pack produced no bundle" outage shape. Adds packer.py to the trigger paths.

Empirical validation

Check Result
Recompile scope exactly 6 files; no compiler/firewall re-stamp
Pin propagation 9 uses: sites @ d723bb64, 6 apm-version @ 0.14.0; zero stale v1.7.2/0.12.4/b48dd081
Trap @ v1.10.0 PASSES — detects .zip + .tar.gz; producer .zip in set
Trap @ v1.7.2 (counterfactual) FAILS — detects only .tar.gz — proves it's a real guard
YAML / JSON parse all changed files parse
ASCII clean

Decisions taken (maintainer-approved)

  • Approved the 0.12.4 -> 0.14.0 apm-version default side-effect of the pin bump.
  • Folded the pack-format trap into this PR (it guards the very pin this PR bumps) rather than a separate PR.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Propagates the released apm-action v1.10.0 (.zip bundle detection) into
the shared workflow and lands a cross-repo guard against the outage shape
that motivated it.

shared/apm.md:
- Pin microsoft/apm-action@v1.7.2 -> @v1.10.0 (5 references).
- apm-version schema default '0.12.4' -> '0.14.0' in lockstep (Job Set C
  requires the schema default to mirror the pinned action's apm-version
  default; v1.10.0 ships 0.14.0). Non-opting gh-aw consumers now default
  to apm CLI 0.14.0.

Recompiled the 3 apm-action consumer locks on gh-aw v0.80.9 (docs-sync,
pr-review-panel, triage-panel): apm-action@d723bb64 # v1.10.0 and
apm-version 0.14.0 at all call sites. actions-lock.json re-keyed to the
v1.10.0 SHA. No compiler/firewall churn -- pin/version-scoped only.

verify-shared-apm-matrix.yml -- new Job Set D (pack-format consumer
compat): cross-references the producer default archive format in
src/apm_cli/bundle/packer.py (.zip) against the archive-extension set the
pinned apm-action release detects (src/bundler.ts ARCHIVE_EXTENSIONS).
Fails on the 'apm pack produced no bundle' outage shape. Empirically
validated: PASSES at @v1.10.0 (detects .zip + .tar.gz), FAILS at @v1.7.2
(detects only .tar.gz) -- a real guard, green only because of this bump.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 25, 2026 19:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates this repo’s gh-aw shared workflow + consumer locks to align with microsoft/apm-action@v1.10.0 (adds .zip bundle detection) and adds a CI drift trap to prevent the “apm pack produced no bundle” outage shape from reoccurring.

Changes:

  • Bump microsoft/apm-action pin v1.7.2 -> v1.10.0 and align the shared apm-version schema default to 0.14.0.
  • Recompile gh-aw consumer lock workflows so their pinned action SHA/version and apm-version inputs match.
  • Add Job Set D to verify-shared-apm-matrix.yml to cross-check APM CLI default archive format vs apm-action’s archive extension detection.
Show a summary per file
File Description
.github/workflows/verify-shared-apm-matrix.yml Adds Job Set D drift guard comparing producer default archive format to apm-action’s detected archive extensions.
.github/workflows/shared/apm.md Bumps apm-action pin to v1.10.0 and updates apm-version schema default to 0.14.0.
.github/workflows/triage-panel.lock.yml Updates pinned microsoft/apm-action SHA/version and apm-version usage to match the new pin.
.github/workflows/pr-review-panel.lock.yml Same pin + apm-version propagation update as above.
.github/workflows/docs-sync.lock.yml Same pin + apm-version propagation update as above.
.github/aw/actions-lock.json Updates the action lock entry key/version/SHA for microsoft/apm-action@v1.10.0.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment thread .github/workflows/shared/apm.md Outdated
Comment on lines +476 to +480
@@ -477,7 +477,7 @@ steps:
[ ${#list[@]} -gt 0 ] || { echo '::error::no apm bundles found'; exit 1; }
printf '%s\n' "${list[@]}" > /tmp/gh-aw/apm-bundle-list.txt
- name: Restore APM packages (all bundles)
uses: microsoft/apm-action@v1.7.2
uses: microsoft/apm-action@v1.10.0

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch -- fixed in e77af32. The "Build bundle list" step now collects both extensions: find ... \( -name '*.tar.gz' -o -name '*.zip' \). apm-action@v1.10.0 restores both natively, so a caller on a zip-default apm-version no longer hits 'no apm bundles found'. Recompiled the 3 consumer locks.

Comment on lines +423 to +432
# Producer side (source of truth in THIS repo): the default archive
# format 'apm pack --archive' emits when --archive-format is omitted.
producer_fmt=$(grep -m1 -E '^[[:space:]]*archive_format: str = "' \
src/apm_cli/bundle/packer.py | sed -E 's/.*= "([^"]+)".*/\1/')
case "$producer_fmt" in
zip) producer_ext=".zip" ;;
tar.gz) producer_ext=".tar.gz" ;;
"") echo "::error file=src/apm_cli/bundle/packer.py::could not read archive_format default"; exit 1 ;;
*) echo "::error file=src/apm_cli/bundle/packer.py::unrecognized archive_format default '$producer_fmt'"; exit 1 ;;
esac

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed -- fixed in e77af32. The guard now reads the producer default from the --archive-format Click option in src/apm_cli/commands/pack.py (the user-facing default apm-action actually invokes, since it omits --archive-format), and additionally asserts the bundle/packer.py dataclass default stays consistent so a future split fails loudly here too.

danielmeppiel and others added 2 commits June 25, 2026 21:33
…ft source

Two Copilot review findings on #1907, both correctness-relevant:

1. shared/apm.md "Build bundle list" collected only '*.tar.gz', so a caller
   that sets apm-version to a zip-default release (apm >= 0.20, or 'latest')
   would pack .zip bundles that this glue step never finds -> 'no apm bundles
   found' even though apm-action@v1.10.0 restores .zip natively. Now matches
   both: find ... \( -name '*.tar.gz' -o -name '*.zip' \). Recompiled the 3
   consumer locks.

2. Job Set D read the producer default from the bundle/packer.py dataclass,
   but apm-action invokes `apm pack --archive` WITHOUT --archive-format, so
   the authoritative default is the Click option default in commands/pack.py.
   The guard now reads commands/pack.py as source of truth and asserts the
   packer.py dataclass default stays consistent (fails loudly on a split).

Validated locally: producer extraction reads 'zip' from commands/pack.py;
consistency check passes; recompile scope is pin-neutral (5 files); YAML
parses; ASCII-clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fold convergent panel hardening into Job Set D (advisory review on #1907):

- Producer extraction reads the whole @click.option("--archive-format")
  block (sed range to next decorator/def) instead of a fixed -A8 window,
  so reordering option kwargs cannot slip default= out of range
  (python-architect, recommended).
- packer.py dataclass consistency check now fails loud when the field is
  absent rather than silently skipping -- the sub-guard can no longer go
  inert undetected (python-architect + cli-logging-expert, convergent).
- Consumer fetch resolves the apm-action tag to the immutable SHA pinned
  in actions-lock.json (falls back to the tag only if absent), so the
  drift source is read at the exact commit the workflows execute, not a
  mutable tag (supply-chain-security-expert).
- ARCHIVE_EXTENSIONS / endsWith parse accepts single- OR double-quoted
  literals so a prettier reformat in apm-action cannot blind the guard;
  consumer echo names src/bundler.ts and the resolved ref
  (python-architect + cli-logging-expert nits).

All four folds smoke-tested locally: producer=zip, packer consistency OK,
SHA fetch @d723bb64 detects {.zip,.tar.gz} -> guard PASSES, double-quote
reformat still parses. No behavior change to the green path; pure
fail-loud + forward-compat hardening.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

APM Review Panel -- advisory recommendation

Ship recommendation: ship_now

Propagates the healed apm-action pin to v1.10.0, locksteps the gh-aw apm-version schema default to 0.14.0, and installs a cross-repo pack-format drift trap (Job Set D) so the producer/consumer archive format can never silently diverge.

Six active panelists converged with zero blocking findings. The single recommended-severity finding and the highest-signal nits were folded in fa90bbe65 before synthesis; CI is green on that commit including the new Job Set D.

Panelist summary

Persona Active blocking / recommended / nit Summary
Python Architect yes 0 / 1 / 2 CI-only; no runtime architecture impact. Flagged shell-extraction fragility (fixed).
CLI Logging Expert yes 0 / 0 / 2 Job Set D failure output is actionable (prints producer default, consumer set, pinned ref). One silent-skip (fixed).
DevX UX Expert yes 0 / 0 / 2 Default bump properly lockstepped and non-breaking -- 0.14.0 is still a .tar.gz-default apm, so non-opting consumers do not silently switch format.
Supply-Chain Security yes 0 / 0 / 2 SHA-pinning enforced at all execution sites. Drift-trap mutable-tag fetch (exploitability nil) hardened to immutable SHA.
Doc Writer yes 0 / 0 / 0 Version prose internally consistent, Job Set D header matches its shell, no doc drift, pure ASCII. Explicit ship.
OSS Growth / Auth / Performance / Test-Coverage no -- Inactive: infra-only PR, no src/ runtime change, no auth surface, no hot path.

Drift-trap data flow

flowchart TD
    A["CI trigger: change to shared/apm.md or bundle/packer.py"] --> C
    C["sed block-read commands/pack.py\n--archive-format Click default"] --> D{producer_fmt empty?}
    D -- yes --> ERR1["::error could not read CLI default -- exit 1"]
    D -- no --> F["grep packer.py dataclass default"]
    F --> G{absent OR != producer?}
    G -- yes --> ERR2["::error fail loud -- exit 1"]
    G -- no --> H["resolve apm-action ref -> immutable SHA\nfrom actions-lock.json"]
    H --> J["gh api bundler.ts @ SHA -> base64 -d"]
    J --> L["parse ARCHIVE_EXTENSIONS\n(single- or double-quoted)"]
    L --> P{producer ext in detected set?}
    P -- yes --> OK["[OK] no drift"]
    P -- no --> ERR5["::error 'apm pack produced no bundle' shape -- exit 1"]
Loading

Folded before ship (commit fa90bbe65, CI green incl Job Set D)

  1. Producer extraction reads the whole @click.option("--archive-format") block (sed range to next decorator/def) instead of a fixed -A8 window -- kills option-reordering fragility (python-architect, recommended).
  2. packer.py consistency check now fails loud when the field is absent rather than silently skipping (python-architect + cli-logging-expert, convergent).
  3. Consumer fetch resolves the apm-action tag to the immutable SHA pinned in actions-lock.json (tag fallback only if absent) (supply-chain-security-expert).
  4. ARCHIVE_EXTENSIONS / endsWith parse accepts single- or double-quoted literals so a prettier reformat cannot blind the guard; consumer echo names src/bundler.ts + resolved ref (python-architect + cli-logging-expert).

Optional follow-ups (non-blocking, defer at will)

  • Decouple the schema description example from the default value so they do not drift together on the next bump (devx-ux).
  • Pin actions/checkout@v4 to a full SHA in verify-shared-apm-matrix.yml (pre-existing, out of scope) (supply-chain-security).
  • Add a CHANGELOG note for the .zip forward-compat in the bundle glob (devx-ux).

Principle alignment

  • Secure by default: SHA-pinning at all execution sites; drift-trap fetch resolves to the immutable SHA.
  • Governed by policy: Job Set D encodes the producer/consumer format contract as a CI-enforced invariant -- a violation surfaces as a loud workflow failure, not a silent runtime mismatch.
  • Portable by manifest: the schema default bump keeps the declared apm-version in lockstep with the pinned action.

Advisory panel -- surfaces findings and a ship recommendation; does not gate merge. cc @danielmeppiel @sergio-sisternes-epam

…out v7

Job Set C's drift guard asserted shared/apm.md's apm-version default ==
apm-action's own action.yml default. Version equality is neither
necessary nor sufficient to catch the "apm pack produced no bundle"
outage: Pack and Restore both receive the one substituted apm-version so
they cannot skew, and apm-action restores whatever format it detects.
Equality false-passes when apm-action keeps an old default but drops a
format, and false-fails on a harmless version diff.

Replace it with the real contract: the pack format the default
apm-version PRODUCES (>= 0.20.0 -> .zip per BREAKING #1720, else
.tar.gz) must be in the pinned apm-action's detected ARCHIVE_EXTENSIONS
set -- the same check Job D runs for this repo's CLI default. This frees
the default from apm-action's own default, so bump it 0.14.0 -> 0.21.0
(the repo's current CLI line) so the non-opting consumer path actually
exercises the shipped .zip pack format. Recompiled the 3 consumer locks
(docs-sync, pr-review-panel, triage-panel) to substitute 0.21.0.

Empirically proven: reframed Job C PASSES at v1.10.0+0.21.0 (.zip in
{.zip,.tar.gz}) and FAILS at v1.7.2+0.21.0 (.zip not in {.tar.gz}) --
the exact original outage shape, confirming the guard is real.

Also pin actions/checkout@v4 -> v7 (SHA 9c091bb # v7.0.0) in Job C and
Job D to match the repo's dominant checkout convention.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel danielmeppiel merged commit 30fb2b1 into main Jun 25, 2026
20 checks passed
@danielmeppiel danielmeppiel deleted the bump-apm-action-v1.10.0 branch June 25, 2026 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants