feat: add pack and restore modes for CI/CD bundle workflows#6
Merged
Conversation
- Add 'pack' input to run 'apm pack' after install/compile steps - Add 'bundle' input for restore mode (extract pre-built bundle, skip APM install) - Add 'target' and 'archive' inputs to control pack behavior - Add 'bundle-path' output for artifact upload integration - New src/bundler.ts module with resolveLocalBundle, extractBundle, runPackStep - Restore mode: tries 'apm unpack' first, falls back to 'tar xzf' - Path traversal protection on bundle resolution - Mutual exclusivity check: pack and bundle cannot be used together - 12 unit tests covering all new code paths - CI integration tests: test-pack and test-restore-artifact jobs - Downgrade @actions/glob to 0.5.0 (CJS compat with Jest/ts-jest) - Updated README with pack mode, restore mode, cross-job examples
Contributor
There was a problem hiding this comment.
Pull request overview
Adds “pack” and “restore” operational modes to this GitHub Action to enable cross-job APM bundle workflows (produce a bundle in one job, restore primitives in another) while keeping existing install/compile/script behavior intact.
Changes:
- Introduces new bundling utilities to resolve bundle globs, extract bundles, and run
apm pack. - Updates the runner flow to early-exit in restore mode and to optionally run pack mode after installation.
- Adds docs, CI integration jobs, and dependency updates to support glob-based bundle resolution.
Reviewed changes
Copilot reviewed 7 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/runner.ts | Adds mode detection (pack vs bundle), restore early-exit path, and optional pack step/output. |
| src/bundler.ts | New module implementing bundle resolution (glob), extraction (apm unpack or tar), and pack output discovery. |
| src/tests/bundler.test.ts | Unit tests covering bundle resolving, extraction paths, and pack invocation behavior. |
| package.json | Adds @actions/glob dependency for bundle path globbing. |
| package-lock.json | Locks @actions/glob and transitive deps for reproducible installs. |
| action.yml | Declares new inputs (pack, bundle, target, archive) and new output (bundle-path). |
| README.md | Documents pack/restore usage patterns and cross-job artifact workflow. |
| .github/workflows/ci.yml | Adds integration jobs for pack and restore workflows; updates release job dependencies. |
| dist/index.js | Updates bundled action artifact to include new bundler logic and glob dependency. |
| dist/bundler.d.ts | Generated type declarations for the new bundler module. |
| dist/runner.d.ts | Updates runner doc comments in generated types. |
| dist/licenses.txt | Adds license texts for newly bundled dependencies. |
Comments suppressed due to low confidence (1)
src/bundler.ts:82
- The
tarfallback extracts an untrusted archive directly into the workspace. Even with-Cand--strip-components, tar archives can contain absolute paths or..segments that write outsideoutputDir. Before extracting, list entries (e.g. viatar -tzf) and validate there are no absolute paths /../ drive prefixes, or extract into a temp dir and only move the expected.github/+.claude/directories into place.
// Fallback: tar extraction
core.info('APM not available — extracting with tar (no verification)...');
const rc = await exec.exec('tar', ['xzf', resolvedBundle, '-C', resolvedOutput, '--strip-components=1'], {
ignoreReturnCode: true,
});
if (rc !== 0) {
throw new Error(`tar extraction failed with exit code ${rc}`);
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Use path.relative() instead of startsWith() for workspace containment (prevents prefix bypass like /workspace vs /workspace-evil) - Error when multiple .tar.gz archives found in build directory - Error when multiple bundle directories found in build directory - Add 2 new tests for ambiguous bundle detection (14 total)
- @actions/core 1.11.1 → 2.0.3 - @actions/exec 1.1.1 → 2.0.0 - @actions/io 1.1.3 → 2.0.0 Note: v3.0.0 of these packages are ESM-only, incompatible with Jest/ts-jest CJS environment and ncc bundling.
- Upgrade @actions/core, exec, io to 3.0.0 and glob to 0.6.1 (ESM) - Add "type": "module" to package.json - Set module/moduleResolution to nodenext in tsconfig.json - Add .js extensions to relative imports (main.ts, runner.ts) - Rewrite tests with jest.unstable_mockModule and @jest/globals - Configure jest for ESM (useESM, extensionsToTreatAsEsm) - Remove @types/jest in favor of @jest/globals - ncc produces ESM bundle (dist/package.json has type:module) - Eliminates transitive undici vulnerability (0 vulnerabilities) - Keeps using: node20 in action.yml for backward compatibility
- action.yml: using node24 (was node20) - ci.yml: node-version 24, concurrency groups (cancel-in-progress on PRs), timeout-minutes on all jobs (10 build, 5 integration/release) - package.json: @types/node ^24.0.0 - Rebuilt dist/ with Node 24 to match CI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two new operational modes to the action — pack and restore — enabling CI/CD workflows that build APM bundles in one job and deploy them in another, without reinstalling APM.
New Inputs
packapm packafter install/compile stepsbundletargetapm pack --targetarchive.tar.gzarchive (default: true)New Output
bundle-pathactions/upload-artifact)How It Works
Pack Mode (
pack: 'true')Runs after existing install/compile steps. Executes
apm pack, locates the output bundle, and setsbundle-pathoutput for downstream artifact upload.Restore Mode (
bundle: '*.tar.gz')Skips APM installation entirely. Resolves the glob to exactly one file, then:
apm unpack(verified extraction)tar xzf(unverified, for environments without APM)Cross-Job Workflow
Implementation
src/bundler.ts— New module withresolveLocalBundle(),extractBundle(),runPackStep()+ helperssrc/runner.ts— Updated flow: restore mode early-exit → existing install → optional pack steppackandbundlecannot be used togetherTesting
src/__tests__/bundler.test.tscovering all code pathstest-packandtest-restore-artifactVerification
dist/index.js)Notes
@actions/globfrom 0.6.1 → 0.5.0 (v0.6.x is ESM-only, incompatible with Jest/ts-jest CJS environment)