Skip to content

Expose apm-version as an import input on shared/apm.md#1842

Open
Copilot wants to merge 2 commits into
mainfrom
copilot/add-apm-version-input
Open

Expose apm-version as an import input on shared/apm.md#1842
Copilot wants to merge 2 commits into
mainfrom
copilot/add-apm-version-input

Conversation

Copilot AI commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Description

Consumers vendor shared/apm.md and import it from their agentic workflows, but the apm CLI version was pinned only via microsoft/apm-action's built-in default. Opting into a newer CLI (e.g. for package knowledge-base files or skill-bundle link-rewriting fixes) required hand-editing the vendored file — fragile, since gh aw update re-merges from upstream and --no-merge reverts it.

This adds apm-version as a first-class, optional import input and threads it into both apm-action invocations.

  • Schema: added optional apm-version (string) to import-schema. Omit to fall through to the action's pinned default.
  • Pack + Restore parity: threaded apm-version: ${{ github.aw.import-inputs.apm-version }} into both apm-action steps so the pack and restore CLI versions cannot skew.
  • Header docs: added usage form 5 to the self-documenting comment block.

Consumers set it cleanly in their import, surviving gh aw update:

imports:
  - uses: shared/apm.md
    with:
      apm-version: '0.20.0'
      target: copilot
      packages:
        - example.ghe.com/<org>/<package>

The microsoft/apm-action@<tag> ref itself remains unparameterized (gh-aw SHA-pins the literal uses: ref at compile time); this covers the common case — a newer CLI on the existing action.

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Maintenance / refactor

Testing

  • Tested locally
  • All existing tests pass
  • Added tests for new functionality (if applicable)

Validated the frontmatter YAML still parses and that apm-version is registered in import-schema. No test infrastructure covers shared/apm.md; the change is additive and optional.

Spec conformance (OpenAPM v0.1)

If this PR changes behaviour that an OpenAPM v0.1 req-XXX covers,
confirm the three-step ritual (see CONTRIBUTING.md "Adding or
changing a normative requirement"):

  • Spec edit: docs/src/content/docs/specs/openapm-v0.1.md updated
    (new/changed <a id="req-XXX"></a> anchor + prose + Appendix C
    row).
  • Manifest edit: docs/src/content/docs/specs/manifests/openapm-v0.1.requirements.yml
    updated.
  • Test edit: a @pytest.mark.req("req-XXX") test under
    tests/spec_conformance/ added or extended.
  • CONFORMANCE.{md,json} regenerated via
    uv run --extra dev python -m tests.spec_conformance.gen_statement
    and committed.
  • N/A -- this PR does not change OpenAPM-observable behaviour.

Co-authored-by: danielmeppiel <51440732+danielmeppiel@users.noreply.github.com>
Copilot AI changed the title [WIP] Expose apm-version as an import input on shared/apm.md Expose apm-version as an import input on shared/apm.md Jun 19, 2026
Copilot AI requested a review from danielmeppiel June 19, 2026 08:59
@danielmeppiel danielmeppiel added the panel-review Trigger the apm-review-panel gh-aw workflow label Jun 19, 2026
@github-actions

Copy link
Copy Markdown

APM Review Panel: needs_rework

PR threads apm-version across pack/restore steps -- a genuine reproducibility win -- but the empty-string pass-through likely floats all non-opting consumers to 'latest', inverting the PR's core promise.

cc @danielmeppiel -- a fresh advisory pass is ready for your review.

Four panelists independently converged on the empty-string contract risk, and the supply-chain expert traced it to a concrete code path: installer.ts in apm-action resolves '' || 'latest', meaning consumers who omit apm-version do NOT receive the action's pinned default -- they receive a floating resolution to the latest release. This directly contradicts the PR description ('action's pinned default applies when omitted') and converts a zero-opt-in deployment into a reproducibility hazard for every consumer of the shared workflow. The fix is bounded: add a conditional guard at the shared-workflow layer so apm-version is only forwarded to the apm-action with: block when the input is non-empty, or introduce a schema default that resolves explicitly to the pinned action version rather than empty string. Either path is a one-to-three-line change.

The remaining panel signals are cohesive and low-controversy. Four panelists independently flagged the header comment '(newer than the action's default)' as misleading -- it implies version pinning is upgrade-only, when it is a bidirectional override. Three panelists noted that version format is ambiguous (v-prefixed tag vs bare semver, behavior of 'latest') and that consumers will hit opaque apm-action errors without explicit format guidance; a sentence in the inline documentation is the minimum viable fix. The oss-growth-hacker and doc-writer both flag the missing CHANGELOG entry and gh-aw.md update, which are required before this input can be considered discoverable by the community.

Strategically, the feature design is sound. Threading apm-version into both pack and restore steps removes the hand-edit-and-re-merge tax on CLI upgrades, strengthens the portable-by-manifest story, and is a concrete operational win for enterprise consumers who need reproducible CI. The PR should stay in draft until the empty-string guard is in place, then the cosmetic and documentation items should be folded in the same pass before it leaves draft review.

Dissent. No genuine inter-panelist disagreement. All four specialists who flagged the empty-string contract converged on the same finding at the same recommended tier; the supply-chain expert provided the deepest trace (installer.ts code path) but the conclusion is consistent across all four. The only framing variance is that supply-chain described the finding as directly contradicting the PR's stated claim while the others framed it as an undocumented implicit contract -- given the installer.ts evidence, the supply-chain framing is more accurate and governs arbitration weight.

Aligned with: Portable-by-manifest (positive when empty-string guard lands -- CLI version becomes a first-class manifest declaration rather than an implicit action default), Secure-by-default (concern: empty-string resolution floats to 'latest', the opposite of secure-by-default; guard required), Governed-by-policy (concern: floating to 'latest' bypasses enterprise reproducibility and audit expectations).

Growth signal. Once the empty-string guard lands, the CHANGELOG headline should frame this as 'pin your CLI version in one place, propagate to all pack/restore steps automatically' -- this directly addresses a known friction point for consumers who have been hand-editing per-step version strings across workflow updates, and reinforces APM's reproducibility narrative.

Panel summary

Persona B R N Takeaway
Python Architect 0 2 2 Clean additive schema extension; main risk is empty-string pass-through to apm-action when apm-version is unset -- correctness is an undocumented apm-action contract.
CLI Logging Expert 0 2 1 Clean additive workflow plumbing change with no Python CLI surface; two observability gaps: no ::notice when apm-version is pinned, and no format guard before value propagates to apm-action.
DevX UX Expert 0 2 1 Good input name; three UX gaps: directional header comment, silent empty-string passthrough contract, and missing format/error guidance for invalid versions.
Supply Chain Security Expert 0 3 2 Low-risk new attack surface (version is workflow-author-controlled); three findings on floating resolution, TOCTOU risk, and missing semver guard.
OSS Growth Hacker 0 2 0 Strong adoption unlock: removes the hand-edit-and-re-merge tax for CLI upgrades. Two discoverability gaps: no CHANGELOG entry and gh-aw.md docs omit the new input.
Doc Writer 0 1 2 Inline documentation is accurate and structurally consistent; one recommended fix on the misleading heading parenthetical, two nits on capitalization and example clarity.

B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.

Top 5 follow-ups

  1. [Supply Chain Security Expert + Python Architect + DevX UX Expert + CLI Logging Expert] (blocking-severity) Add a conditional guard so apm-version is only forwarded to the apm-action with: block when the input is non-empty -- installer.ts resolves '' || 'latest', so all non-opting consumers currently float to the latest CLI release, silently contradicting the PR's stated guarantee and the secure-by-default principle.
  2. [CLI Logging Expert + DevX UX Expert + Doc Writer + Supply Chain Security Expert] Reword the header comment from '(newer than the action's default)' to a neutral override description (e.g. '(overrides the action's built-in default)') -- four panelists independently flagged this as misleading, and it is a one-line fix.
  3. [OSS Growth Hacker + Doc Writer] Add a CHANGELOG entry for the new apm-version import input and update gh-aw.md to surface it to incoming consumers -- user-visible import inputs require CHANGELOG coverage and gh-aw.md is the canonical consumer discovery surface.
  4. [Python Architect + DevX UX Expert + Supply Chain Security Expert] Document the accepted version string format (v-prefixed vs bare semver) and explicitly caution that 'latest' resolves dynamically at run time -- consumers will hit opaque downstream errors without format guidance and 'latest' introduces TOCTOU float risk that contradicts the feature's pinning intent.
  5. [CLI Logging Expert] Emit a ::notice log line in the apm-prep compute step when apm-version is explicitly pinned -- consistent with the existing matrix observability pattern used for other key configuration dimensions.

Architecture

classDiagram
    class ImportSchema {
        +packages array
        +appId string
        +owner string
        +target string
        +apmVersion string
    }
    class ImportInputs {
        +packages list
        +target string
        +apmVersion string
    }
    class CredentialGroup {
        +id string
        +kind string
        +index int
        +packages list
    }
    class PackStep {
        +uses string
        +apmVersion string
        +dependencies string
        +isolated bool
        +pack bool
        +target string
    }
    class RestoreStep {
        +uses string
        +apmVersion string
        +bundlesFile string
    }
    class ApmAction {
        +apmVersion string
        +installCLI()
        +packDependencies()
        +restoreBundles()
    }
    ImportSchema --> ImportInputs : gh-aw compile
    ImportInputs --> CredentialGroup : apm-prep normalises
    CredentialGroup --> PackStep : matrix fan-out
    PackStep --> ApmAction : invokes
    RestoreStep --> ApmAction : invokes
    ImportInputs ..> PackStep : apmVersion threads to
    ImportInputs ..> RestoreStep : apmVersion threads to
Loading
flowchart TD
    A[Consumer: imports shared/apm.md\nwith apm-version input] --> B[gh aw update: compile-time substitution]
    B -->|import-inputs resolved| C[Compiled .lock.yml: apm-version inlined or empty]
    C --> D[apm-prep job: compute credential matrix]
    D -->|matrix fan-out| E[apm job per CredentialGroup]
    E --> F[Pack via apm-action@v1.7.2]
    F --> G[Bundle artifact: apm-groupid.tar.gz]
    C --> H[pre-agent steps]
    G -->|download| H
    H --> I[Restore via apm-action@v1.7.2]
    I --> J[Agent filesystem: .apm bundle unpacked]
    style F fill:#d4edda
    style I fill:#d4edda
Loading

Recommendation

The PR is correctly in draft. One behavioral correctness issue must be resolved before it leaves draft: the empty-string pass-through to apm-action, where installer.ts resolves '' || 'latest', silently floats all non-opting consumers to the latest CLI release -- the opposite of the stated guarantee. Once a conditional guard or explicit schema default is in place, three items should be folded in the same pass before leaving draft: reword the misleading header comment, add the CHANGELOG entry and gh-aw.md update, and document the accepted version format. The underlying feature design is clean and worth shipping fast once the behavioral fix lands.


Full per-persona findings

Python Architect

  • [recommended] Empty-string pass-through when apm-version is omitted is an undocumented behavioral contract with apm-action at .github/workflows/shared/apm.md
    import-schema declares apm-version with required: false and no default: value. When a consumer omits apm-version, gh-aw substitutes an empty string; every compiled lock file for non-opting consumers will silently gain apm-version: '' on both apm-action invocations. Correctness depends entirely on apm-action@v1.7.2 treating '' as 'use pinned default'; this is a behavioral contract not documented in the schema description.
    Suggested: Document the empty-string semantics explicitly in the description field, or add a guard step in the workflow body that only forwards apm-version to the with: block when the resolved input is non-empty.

  • [recommended] Version string format (bare semver vs v-prefixed tag) is ambiguous in the docs at .github/workflows/shared/apm.md
    The header comment and schema description show '0.20.0' (bare semver) but release tags use 'v0.20.0' (v-prefixed); these forms may or may not be interchangeable depending on how apm-action resolves the version.
    Suggested: Extend the description to state the accepted canonical form explicitly; if both are valid, say so.

  • [nit] Header pin comment should note the minimum apm-action version that accepts the apm-version input at .github/workflows/shared/apm.md
    Consumers who vendor an older pin would silently have the input ignored (unknown inputs are not errors in GitHub Actions).
    Suggested: Append to the pin-comment block: # apm-version input: accepted by microsoft/apm-action@v1.7.2 and above.

  • [nit] In-repo compiled lock files are not regenerated by this PR
    Expected for an opt-in input; lock files should be regenerated via gh aw update post-merge so consumers see the new behavior in the canonical reference.

CLI Logging Expert

  • [recommended] No ::notice emitted when apm-version is pinned, breaking existing observability pattern at .github/workflows/shared/apm.md
    The Compute APM credential-group matrix step already emits structured ::notice lines for key configuration decisions. apm-version is equally decision-critical; without a companion notice, operators must spelunk into the apm-action step log to determine which CLI version was installed.
    Suggested: Add a ::notice line in the apm-prep compute step that logs the resolved apm-version value -- either the pinned value or an explicit note that the apm-action default is in effect.

  • [recommended] apm-version passed to apm-action with no format guard -- consumer typos produce opaque downstream errors at .github/workflows/shared/apm.md
    Every other validated input in the compute step uses early ::error:: with actionable remediation. apm-version receives no validation; typos like 'v0.20.0', '0.20', or 'latest' propagate silently. Empty-string behavior when apm-version is omitted is also unconfirmed.
    Suggested: Add a semver format guard in the compute step and confirm with apm-action maintainers that an empty-string apm-version is equivalent to omitting the input.

  • [nit] Header comment '(newer than the action's default)' implies version must be newer -- not technically required at .github/workflows/shared/apm.md
    Suggested: Change to '(overrides the action's built-in default)'.

DevX UX Expert

  • [recommended] Empty-string passthrough behaviour is an undocumented implicit contract with apm-action at .github/workflows/shared/apm.md
    When a consumer omits apm-version, ${{ github.aw.import-inputs.apm-version }} resolves to '' and is passed verbatim to both apm-action with: blocks. Whether apm-action treats '' as 'use pinned default' is invisible to the consumer and fragile if the action changes its handling.
    Suggested: Add a one-line note to the schema description, or guard at the step level so the key is only emitted when the consumer actually provided a value.

  • [recommended] No format guidance or error signal documented for invalid version strings at .github/workflows/shared/apm.md
    The schema shows '0.20.0' but does not state whether v0.20.0 is accepted. Errors for non-existent versions surface deep in CI logs far from the import declaration -- unlike npm/pip/cargo which surface version errors close to the declaration.
    Suggested: State whether v-prefix is accepted and add a note about what the consumer sees for an invalid version.

  • [nit] Header comment says 'newer than the action's default' -- implies upgrade-only, which contradicts the input's bidirectional nature at .github/workflows/shared/apm.md
    Suggested: Drop the parenthetical or change to '# 5. Pin a specific apm CLI version:'.

Supply Chain Security Expert

  • [recommended] Schema omits default: -- when apm-version is unset, installer.ts resolves 'latest' rather than the action's pinned default at .github/workflows/shared/apm.md
    The target schema sibling has default: all; apm-version has no default:. In apm-action installer.ts: const apmVersionInput = (core.getInput('apm-version') || 'latest').trim() -- an empty string bypasses the action.yml default of 0.12.4 and falls into the 'latest' path, directly contradicting the PR description.
    Suggested: Add a conditional guard so apm-version is only forwarded to the with: block when the import-input is non-empty, preventing empty-string bypass of the action's own default.

  • [recommended] Schema accepts 'latest' as a valid value without warning -- TOCTOU float risk at .github/workflows/shared/apm.md
    apm-action@v1.7.2 has a 'latest' branch that hits the GitHub Releases API at run time. A consumer passing 'latest' gets a different binary on every re-run, contradicting the pinning intent of the feature.
    Suggested: Extend the schema description to document the float risk and caution against 'latest'. Consider a pattern: constraint to reject the string at the schema layer.

  • [recommended] No semver format guard at the shared-workflow layer -- version string flows raw to a URL constructor in installer.ts at .github/workflows/shared/apm.md
    The parallel target input is validated with a regex before use. apm-version has no equivalent guard; the string is used to construct a release download URL and as a tool-cache key, both sensitive to malformed input.
    Suggested: Add a schema-level pattern constraint (e.g. pattern: '^v?\d+\.\d+\.\d+[\w.+-]*$') so gh-aw rejects non-semver version strings before they reach the action.

  • [nit] Both apm-action references use mutable tag v1.7.2 rather than a commit SHA (pre-existing) at .github/workflows/shared/apm.md
    Suggested: Replace with SHA-pinned refs: uses: microsoft/apm-action@<SHA> # v1.7.2.

  • [nit] Example comment says 'newer than the action's default' -- implies an unenforced directional constraint at .github/workflows/shared/apm.md
    Suggested: Change to 'override the action's pinned default'.

OSS Growth Hacker

  • [recommended] No CHANGELOG entry for the user-visible apm-version import input at CHANGELOG.md
    CHANGELOG.md [Unreleased] is the primary surface where existing users discover new capabilities. Without an entry the feature cannot be included in the next release narrative.
    Suggested: Add under [Unreleased] > ### Added: 'shared/apm.md now accepts an optional apm-version input that pins the apm CLI version for both the Pack and Restore apm-action steps, surviving gh aw update re-merges. (Expose apm-version as an import input on shared/apm.md #1842)'

  • [recommended] gh-aw.md integration doc does not surface the apm-version input to incoming consumers at docs/src/content/docs/integrations/gh-aw.md
    docs/src/content/docs/integrations/gh-aw.md is the canonical docs entry point for the shared/apm.md integration; without a doc mention the feature is invisible to readers.
    Suggested: Append to the Vendor callout: 'Once vendored, pin the apm CLI version by adding apm-version: "0.x.y" to the import with: block. The pin survives future gh aw update re-merges.'

Doc Writer

  • [recommended] Example 5 heading parenthetical '(newer than the action's default)' implies apm-version is upgrade-only at .github/workflows/shared/apm.md
    Consumers pin for rollback, stability, and reproducibility -- not only to exceed the action default. The schema description correctly says 'Pin explicitly for reproducibility'; the heading contradicts it.
    Suggested: Change to # 5. Pin the apm CLI version (overrides the action's bundled default):

  • [nit] Capitalization inconsistency: new schema comment uses lowercase 'apm' where the adjacent comment uses uppercase 'APM' at .github/workflows/shared/apm.md
    Suggested: Change # apm CLI version to # APM CLI version.

  • [nit] Example 5 inherits target: copilot from example 4, obscuring that apm-version is a standalone feature at .github/workflows/shared/apm.md
    Suggested: Either remove target: copilot to produce the minimal version-pinning example, or retitle to make the combination intentional.

Auth Expert -- inactive

PR #1842 touches only .github/workflows/shared/apm.md to thread an optional apm-version string input into apm-action invocations; no auth files, token resolution paths, or HTTP/git authorization headers are modified.

Test Coverage Expert -- inactive

documentation-only PR -- no runtime code paths to defend

Performance Expert -- inactive

PR changes only a workflow configuration file (apm-version input threading); no install pipeline, cache, or transport paths are touched.

This panel is advisory. It does not block merge. Re-apply the
panel-review label after addressing feedback to re-run.

Generated by PR Review Panel for issue #1842 · sonnet46 13.2M ·

@github-actions github-actions Bot removed the panel-review Trigger the apm-review-panel gh-aw workflow label Jun 19, 2026
@danielmeppiel danielmeppiel marked this pull request as ready for review June 20, 2026 19:53
Copilot AI review requested due to automatic review settings June 20, 2026 19:53

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

This PR updates the vendorable shared workflow .github/workflows/shared/apm.md to expose an optional apm-version import input and thread it into both the pack and restore microsoft/apm-action invocations, enabling consumers to pin the APM CLI version without editing their vendored copy.

Changes:

  • Added a new usage example (form 5) showing how to set apm-version.
  • Extended import-schema with optional apm-version: string.
  • Passed apm-version into both the pack and restore microsoft/apm-action@v1.7.2 steps.
Show a summary per file
File Description
.github/workflows/shared/apm.md Adds apm-version as an import input and wires it into pack/restore apm-action steps, plus updates the header usage docs.

Copilot's findings

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

Comment on lines 392 to 394
with:
apm-version: ${{ github.aw.import-inputs.apm-version }}
dependencies: ${{ steps.list.outputs.deps }}
Comment on lines 471 to 475
- name: Restore APM packages (all bundles)
uses: microsoft/apm-action@v1.7.2
with:
apm-version: ${{ github.aw.import-inputs.apm-version }}
bundles-file: /tmp/gh-aw/apm-bundle-list.txt
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.

3 participants