Skip to content

fix(shared/apm): repair gh-aw [a b] import-input serialization that breaks apm-prep#1033

Merged
danielmeppiel merged 1 commit intomainfrom
fix/apm-import-packages-json
Apr 29, 2026
Merged

fix(shared/apm): repair gh-aw [a b] import-input serialization that breaks apm-prep#1033
danielmeppiel merged 1 commit intomainfrom
fix/apm-import-packages-json

Conversation

@danielmeppiel
Copy link
Copy Markdown
Collaborator

TL;DR

PR #982's new Compute APM credential-group matrix step in shared/apm.md feeds ${{ github.aw.import-inputs.packages }} to jq --argjson. gh-aw substitutes that template at compile time using Go's default slice formatter, which emits [microsoft/apm#main] (space-separated, no quotes) instead of valid JSON. jq rejects it and apm-prep crashes, blocking every pr-review-panel and triage-panel run since lock files were last regenerated.

This PR adds a small repair shim in shared/apm.md and recompiles both lock files. Upstream paper-cut filed at github/gh-aw#29076.

How we got here

Date PR What happened
2026-04-28 #982 Added apm-prep step using --argjson; locks not regenerated, bug latent
2026-04-28 #1026 Recompiled locks to v1.5.0; surfaced bug -- locks now contain AW_APM_PACKAGES: "[microsoft/apm#main]"
2026-04-29 (today) First failing run observed on PR #1031: jq: invalid JSON text passed to --argjson

Pinning gh-aw doesn't help: same compiler version (v0.68.3) produced both shapes -- the difference was that #982 introduced the new compute step that started routing the substituted value through --argjson. The bug is in our shared/apm.md, not in the gh-aw binary -- though the upstream serializer choice is what makes the bug possible (hence github/gh-aw#29076).

What changed

.github/workflows/shared/apm.md            | 20 ++++++++++++++++++++
.github/workflows/pr-review-panel.lock.yml | 20 ++++++++++++++++++++
.github/workflows/triage-panel.lock.yml    | 20 ++++++++++++++++++++

shared/apm.md gains a tiny repair_string_array Bash+Python helper that:

  • passes null and empty values through untouched,
  • passes already-valid JSON (jq -e 'type=="array"') through untouched,
  • otherwise strips outer brackets, splits on whitespace/commas, and re-emits as JSON.

The two consumer lock files are regenerated with gh aw compile pr-review-panel triage-panel. No source change to either pr-review-panel.md or triage-panel.md.

apps[] (object arrays) is not repairable this way -- the Go-slice format for objects is [map[k:v] map[k:v]] and is non-trivially round-trippable. No current workflow uses apps[] via import-inputs (only the legacy single-app inputs are exercised), so this PR leaves apps alone with a comment pointing at the upstream issue.

Verification

End-to-end simulation against the live shared/apm.md run-block:

Input AW_APM_PACKAGES Resulting matrix.group.packages
[microsoft/apm#main] ["microsoft/apm#main"]
[microsoft/apm#main github/awesome-copilot/skills/foo] ["microsoft/apm#main","github/awesome-copilot/skills/foo"]
["already","json"] ["already","json"]
null (no group emitted -- existing 'no packages' error path, unchanged)

Audit of other gh-aw workflows

Only pr-review-panel.md and triage-panel.md import shared/apm.md; cli-consistency-checker.md, daily-doc-updater.md, and daily-test-improver.md do not have any imports: block and are unaffected.

Risk

Low. The repair is fully gated behind an is-this-already-valid-JSON check, so well-formed inputs (today and after upstream fix) are untouched. No changes to schema, no breaking change for vendored copies of shared/apm.md -- the Source of truth/apm-action pin header lines stay byte-identical.

Follow-ups

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

PR #982 added a Compute APM credential-group matrix step that feeds
`${{ github.aw.import-inputs.packages }}` to `jq --argjson`. gh-aw
substitutes that template at compile time using Go's default slice
formatter, which emits `[microsoft/apm#main]` (space-separated, no
quotes) instead of valid JSON `["microsoft/apm#main"]`. jq rejects
the malformed input and apm-prep fails, blocking every PR run of the
review panel and every triage-panel labelled issue.

The bug shipped latent in #982 (locks not regenerated) and surfaced in
#1026 when the locks were recompiled. Pinning gh-aw does not help: the
same compiler version (v0.68.3) produced both shapes -- the difference
was the new compute step that started routing the substituted value
through `--argjson`.

Fix: add a small Bash+Python repair_string_array helper in shared/apm.md
that detects malformed Go-slice strings and rewrites them as JSON before
they reach jq. Already-valid JSON and 'null' pass through untouched.
apps[] (object arrays) is not repairable this way -- consumers must use
the legacy single-app inputs until upstream gh-aw exposes a JSON-encoding
helper for import-inputs (paper-cut filed upstream).

- shared/apm.md: add repair_string_array helper for AW_APM_PACKAGES
- pr-review-panel.lock.yml + triage-panel.lock.yml: recompile

Verified locally with the live shared/apm.md run-block against four
inputs ([single], [multi space-separated], null, already-valid JSON);
all produce a correctly-typed matrix.group.packages array.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 29, 2026 10:58
@danielmeppiel danielmeppiel merged commit 7a1462c into main Apr 29, 2026
17 checks passed
@danielmeppiel danielmeppiel deleted the fix/apm-import-packages-json branch April 29, 2026 11:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Repairs gh-aw import-inputs.packages array substitution so the shared APM workflow can safely pass packages through jq --argjson when gh-aw serializes string slices as Go-style [a b] instead of valid JSON, unblocking apm-prep for downstream panel workflows.

Changes:

  • Added a repair_string_array shim in .github/workflows/shared/apm.md to normalize non-JSON [a b] into JSON ["a","b"] while leaving valid JSON untouched.
  • Regenerated pr-review-panel.lock.yml and triage-panel.lock.yml so the compiled workflows include the shim.
Show a summary per file
File Description
.github/workflows/shared/apm.md Adds a packages input repair step before feeding values into jq --argjson.
.github/workflows/pr-review-panel.lock.yml Regenerated compiled workflow containing the new packages repair shim.
.github/workflows/triage-panel.lock.yml Regenerated compiled workflow containing the new packages repair shim.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 3

if printf '%s' "$raw" | jq -e 'type=="array"' >/dev/null 2>&1; then
echo "$raw"; return
fi
python3 -c 'import json, re, sys; s=sys.argv[1].strip(); s=s[1:-1] if s.startswith("[") and s.endswith("]") else s; print(json.dumps([t for t in re.split(r"[\s,]+", s) if t]))' "$raw"
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

repair_string_array introduces a new runtime dependency on python3, but this job already assumes only bash + jq. On runs-on: ubuntu-slim it's not guaranteed python3 is present, so this can break the workflow even when jq is available. Prefer implementing the repair using jq (already required) or add an explicit command -v python3 check with a clear error (and then recompile the lock workflows).

Suggested change
python3 -c 'import json, re, sys; s=sys.argv[1].strip(); s=s[1:-1] if s.startswith("[") and s.endswith("]") else s; print(json.dumps([t for t in re.split(r"[\s,]+", s) if t]))' "$raw"
printf '%s' "$raw" | jq -Rn '
input
| gsub("^\\s+|\\s+$"; "")
| if startswith("[") and endswith("]") then .[1:-1] else . end
| split("[\\s,]+"; null)
| map(select(length > 0))
'

Copilot uses AI. Check for mistakes.
apps_json=${AW_APM_APPS:-null}
legacy_id=${AW_APM_LEGACY_APP_ID:-}

# gh-aw substitutes `["microsoft/apm#main"]` at
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

The comment claims gh-aw substitutes "[\"microsoft/apm#main\"]"/["microsoft/apm#main"], but the actual substituted value in this workflow is "[microsoft/apm#main]" (no quotes around elements), which is the invalid-JSON shape that breaks jq --argjson. Updating the comment to reflect the real broken format will make future debugging less confusing.

Suggested change
# gh-aw substitutes `["microsoft/apm#main"]` at
# gh-aw substitutes `[microsoft/apm#main]` at

Copilot uses AI. Check for mistakes.
Comment on lines +1070 to +1074
# gh-aw substitutes `["microsoft/apm#main"]` at
# compile time using Go's default slice formatter, which emits
# `[a b c]` (space-separated, no quotes) instead of valid JSON.
# That breaks `jq --argjson` below. Repair string-array inputs
# in place; leave already-valid JSON untouched. apps[] (objects)
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

The comment says the substituted value looks like ["microsoft/apm#main"], but the actual value in this workflow is "[microsoft/apm#main]" (no quotes around elements), which is the invalid JSON that triggers the jq --argjson failure. Please update the comment to match the real broken format so it doesn't imply the input is already valid JSON.

Copilot uses AI. Check for mistakes.
danielmeppiel pushed a commit that referenced this pull request Apr 29, 2026
Promotes [Unreleased] -> [0.11.0] - 2026-04-29 and bumps
pyproject.toml + uv.lock to 0.11.0.

Version-bump rationale: 0.11.0 (minor bump) chosen over 0.10.1 because
this release ships one BREAKING removal (`apm marketplace build` -> exits 2,
use `apm pack`) plus several net-new features (Dev Container Feature,
Codex project-scoped MCP, `marketplace:` block in apm.yml, `apm pack`
unification, multi-org `apps[]`). Strict semver in 0.x: minor for
features-with-break, patch only for bugfixes.

Milestone admin (done out-of-band):
- Renamed milestone #8 `0.10.1` -> `0.11.0`
- Created milestone #9 `0.12.0` as next-up bucket
- Moved 43 open items (42 issues + 1 open PR #999) from `0.11.0` -> `0.12.0`
- 6 closed items stay in `0.11.0`

PRs shipping in 0.11.0 (22 commits since v0.10.0):

User-facing features:
- #1042/#722 `apm pack` unifies bundle + marketplace.json
                   (BREAKING: `apm marketplace build` removed)
- #1038       `marketplace:` block in apm.yml + `apm marketplace migrate`
- #803  /#502 Codex project-scoped MCP (`.codex/config.toml`) + user-scope primitives
- #861        Dev Container Feature `ghcr.io/microsoft/apm/apm-cli`
- #982/#984   shared/apm.md `apps:` array for cross-org private packages
- #820        `target:` in apm.yml validates at parse time
- #1032       `apm marketplace add` honors manifest.name (Claude Code parity)
- #1000/#998/#994 unified `--policy` / `--policy-source` accepted forms

User-facing fixes:
- #1015 ADO Entra ID auth + `apm install --update` pre-flight abort
- #1019/#1020 GEMINI.md only created when target requested
- #1008 marketplace producer respects GITHUB_HOST + multi-host URL forms
- #1018 POSIX paths in auto-discovery output (Windows compat)
- #996  drop stray 'specify' from generated file footer

Maintainer tooling:
- #1043 NOTICE.md per CELA template
- #1045/#1044 NOTICE drift gate + license-policy gate in CI
- #1033 shared/apm.md `[a b]` import-input repair (gh-aw#29076 paper-cut)
- #1030 panel workflows skip-don't-fail on unmatched labels; gh-aw v0.71.1
- #1026 shared/apm.md recompiled to apm-action v1.5.0 + bundles-file
- #1022 review-panel: true fan-out + binary verdict + label automation
- #918  complexity audit + benchmarks suite
- #1002 CodeQL clear-text-storage false-positive resolved (token -> placeholder)

Files changed:
- pyproject.toml: 0.10.0 -> 0.11.0
- uv.lock:        regenerated (version field only)
- CHANGELOG.md:   [Unreleased] promoted to [0.11.0] - 2026-04-29

NOTICE drift check passes against the bumped lockfile.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel danielmeppiel added this to the 0.11.0 milestone Apr 29, 2026
danielmeppiel added a commit that referenced this pull request Apr 29, 2026
…#1051)

* fix(shared/apm): re-shape single-artifact download to expected layout

actions/download-artifact (>=v5) silently overrides 'merge-multiple: false'
and flattens contents directly into 'path/' whenever exactly one artifact
matches the pattern. Our 'Validate downloaded bundles match matrix manifest'
step assumed the per-artifact subdir always exists, so any single-group
consumer (the common case: one credential group, one packed bundle) hits
'missing APM bundles (group did not pack successfully): apm-<id>' even
though the bundle downloaded and verified successfully.

This was latent until #1033 unblocked apm-prep -- previously apm-prep
itself was failing on the malformed jq input, so the agent job never got
far enough to run validation. With prep fixed, every single-group PR run
of pr-review-panel and triage-panel now fails at the validation step.

Fix: add a normalisation step that, when matrix has exactly one group,
re-creates the expected '${prefix}apm-<id>/' subdir and moves the
flattened bundle file(s) into it. No-op for multi-group matrices where
download-artifact already produces per-artifact subdirs. Validation
script is unchanged.

Refs: actions/download-artifact src/download-artifact.ts -- the
'isSingleArtifactDownload || mergeMultiple || artifacts.length === 1'
check that triggers the flatten.

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

* address panel review: restore setup-cli lock entry, harden group_id, changelog

- Restore github/gh-aw-actions/setup-cli@v0.71.2 entry in actions-lock.json
  (still referenced by .github/workflows/agentics-maintenance.yml; the prior
  recompile dropped it because pr-review-panel and triage-panel don't use it).
- Sanitise group_id with strict allowlist (^[A-Za-z0-9_-]+$) before
  interpolating into the shell path, as defence-in-depth even though apm-prep
  produces a sanitised id today.
- Guard jq '.group | length' against null with '.group // []'.
- Link upstream actions/download-artifact source in the comment so future
  maintainers can verify the workaround is still needed.
- CHANGELOG entry under [Unreleased] -> Fixed referencing #1051.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
danielmeppiel pushed a commit that referenced this pull request Apr 29, 2026
Promotes [Unreleased] -> [0.11.0] - 2026-04-29 and bumps
pyproject.toml + uv.lock to 0.11.0.

Version-bump rationale: 0.11.0 (minor bump) chosen over 0.10.1 because
this release ships one BREAKING removal (`apm marketplace build` -> exits 2,
use `apm pack`) plus several net-new features (Dev Container Feature,
Codex project-scoped MCP, `marketplace:` block in apm.yml, `apm pack`
unification, multi-org `apps[]`). Strict semver in 0.x: minor for
features-with-break, patch only for bugfixes.

Milestone admin (done out-of-band):
- Renamed milestone #8 `0.10.1` -> `0.11.0`
- Created milestone #9 `0.12.0` as next-up bucket
- Moved 43 open items (42 issues + 1 open PR #999) from `0.11.0` -> `0.12.0`
- 6 closed items stay in `0.11.0`

PRs shipping in 0.11.0 (22 commits since v0.10.0):

User-facing features:
- #1042/#722 `apm pack` unifies bundle + marketplace.json
                   (BREAKING: `apm marketplace build` removed)
- #1038       `marketplace:` block in apm.yml + `apm marketplace migrate`
- #803  /#502 Codex project-scoped MCP (`.codex/config.toml`) + user-scope primitives
- #861        Dev Container Feature `ghcr.io/microsoft/apm/apm-cli`
- #982/#984   shared/apm.md `apps:` array for cross-org private packages
- #820        `target:` in apm.yml validates at parse time
- #1032       `apm marketplace add` honors manifest.name (Claude Code parity)
- #1000/#998/#994 unified `--policy` / `--policy-source` accepted forms

User-facing fixes:
- #1015 ADO Entra ID auth + `apm install --update` pre-flight abort
- #1019/#1020 GEMINI.md only created when target requested
- #1008 marketplace producer respects GITHUB_HOST + multi-host URL forms
- #1018 POSIX paths in auto-discovery output (Windows compat)
- #996  drop stray 'specify' from generated file footer

Maintainer tooling:
- #1043 NOTICE.md per CELA template
- #1045/#1044 NOTICE drift gate + license-policy gate in CI
- #1033 shared/apm.md `[a b]` import-input repair (gh-aw#29076 paper-cut)
- #1030 panel workflows skip-don't-fail on unmatched labels; gh-aw v0.71.1
- #1026 shared/apm.md recompiled to apm-action v1.5.0 + bundles-file
- #1022 review-panel: true fan-out + binary verdict + label automation
- #918  complexity audit + benchmarks suite
- #1002 CodeQL clear-text-storage false-positive resolved (token -> placeholder)

Files changed:
- pyproject.toml: 0.10.0 -> 0.11.0
- uv.lock:        regenerated (version field only)
- CHANGELOG.md:   [Unreleased] promoted to [0.11.0] - 2026-04-29

NOTICE drift check passes against the bumped lockfile.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
danielmeppiel added a commit that referenced this pull request Apr 29, 2026
* chore(release): cut 0.11.0

Promotes [Unreleased] -> [0.11.0] - 2026-04-29 and bumps
pyproject.toml + uv.lock to 0.11.0.

Version-bump rationale: 0.11.0 (minor bump) chosen over 0.10.1 because
this release ships one BREAKING removal (`apm marketplace build` -> exits 2,
use `apm pack`) plus several net-new features (Dev Container Feature,
Codex project-scoped MCP, `marketplace:` block in apm.yml, `apm pack`
unification, multi-org `apps[]`). Strict semver in 0.x: minor for
features-with-break, patch only for bugfixes.

Milestone admin (done out-of-band):
- Renamed milestone #8 `0.10.1` -> `0.11.0`
- Created milestone #9 `0.12.0` as next-up bucket
- Moved 43 open items (42 issues + 1 open PR #999) from `0.11.0` -> `0.12.0`
- 6 closed items stay in `0.11.0`

PRs shipping in 0.11.0 (22 commits since v0.10.0):

User-facing features:
- #1042/#722 `apm pack` unifies bundle + marketplace.json
                   (BREAKING: `apm marketplace build` removed)
- #1038       `marketplace:` block in apm.yml + `apm marketplace migrate`
- #803  /#502 Codex project-scoped MCP (`.codex/config.toml`) + user-scope primitives
- #861        Dev Container Feature `ghcr.io/microsoft/apm/apm-cli`
- #982/#984   shared/apm.md `apps:` array for cross-org private packages
- #820        `target:` in apm.yml validates at parse time
- #1032       `apm marketplace add` honors manifest.name (Claude Code parity)
- #1000/#998/#994 unified `--policy` / `--policy-source` accepted forms

User-facing fixes:
- #1015 ADO Entra ID auth + `apm install --update` pre-flight abort
- #1019/#1020 GEMINI.md only created when target requested
- #1008 marketplace producer respects GITHUB_HOST + multi-host URL forms
- #1018 POSIX paths in auto-discovery output (Windows compat)
- #996  drop stray 'specify' from generated file footer

Maintainer tooling:
- #1043 NOTICE.md per CELA template
- #1045/#1044 NOTICE drift gate + license-policy gate in CI
- #1033 shared/apm.md `[a b]` import-input repair (gh-aw#29076 paper-cut)
- #1030 panel workflows skip-don't-fail on unmatched labels; gh-aw v0.71.1
- #1026 shared/apm.md recompiled to apm-action v1.5.0 + bundles-file
- #1022 review-panel: true fan-out + binary verdict + label automation
- #918  complexity audit + benchmarks suite
- #1002 CodeQL clear-text-storage false-positive resolved (token -> placeholder)

Files changed:
- pyproject.toml: 0.10.0 -> 0.11.0
- uv.lock:        regenerated (version field only)
- CHANGELOG.md:   [Unreleased] promoted to [0.11.0] - 2026-04-29

NOTICE drift check passes against the bumped lockfile.

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

* chore(changelog): tighten 0.11.0 entries to lead with user impact

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

* chore(changelog): move Dev Container Feature to Maintainer tooling (not yet published)

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

* chore(changelog): de-dupe within 0.11.0 (combine #722 Removed bullets, drop #820 Fixed pointer)

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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