Skip to content

feat: audit hardening — unpack scanning, SARIF/JSON/Markdown output#330

Open
danielmeppiel wants to merge 7 commits intomainfrom
feat/audit-unpack-sarif
Open

feat: audit hardening — unpack scanning, SARIF/JSON/Markdown output#330
danielmeppiel wants to merge 7 commits intomainfrom
feat/audit-unpack-sarif

Conversation

@danielmeppiel
Copy link
Collaborator

@danielmeppiel danielmeppiel commented Mar 16, 2026

Summary

Closes #329

Strengthens apm audit with content scanning during apm unpack, machine-readable SARIF/JSON/Markdown output, and documentation alignment.

Changes

Content scanning for apm unpack

Bundles are now scanned for hidden Unicode characters after extraction, before deployment — matching the apm install pattern. Critical findings block deployment unless --force is used.

  • New security_warnings / security_critical fields on UnpackResult
  • New --force flag on unpack command (audit override)
  • Symlinks are skipped during deploy to prevent scan bypass
  • 6 new tests

apm audit --format sarif/json/markdown --output

Machine-readable output for CI artifact capture, GitHub Code Scanning, and step summaries:

apm audit -f sarif -o audit.sarif  # GitHub Code Scanning
apm audit -f json -o report.json   # Machine-readable
apm audit -f markdown              # Step summaries ($GITHUB_STEP_SUMMARY)
apm audit -f sarif                 # SARIF to stdout
  • --format/-f: text (default), json, sarif, markdown
  • --output/-o: write to file, auto-detects format from extension (.sarif, .json, .md)
  • New src/apm_cli/security/audit_report.py — SARIF 2.1.0 + JSON + Markdown serialization
  • Privacy-safe: relative paths only, no content snippets
  • Incompatible with --strip/--dry-run (validated with error, including auto-detected formats)
  • 22 new tests

PR review fixes

  • Security: Symlinks skipped during unpack deploy (prevents scan bypass)
  • Security: Absolute paths normalized to relative in SARIF/JSON reports
  • Security: Format validation now resolves auto-detected formats before incompatibility check
  • Fixed detect_format_from_extension() to default to text for unknown extensions
  • Fixed error message referencing temp dir path
  • Fixed type annotation in test helper
  • Fixed absolute doc link to relative Starlight link
  • Added symlink test platform skip guard
  • Added PR numbers to CHANGELOG entries

Documentation

  • Fixed apm audit --ci drift — 18+ references across 6 doc files now correctly mark --ci as planned
  • ci-cd.md — SARIF + markdown step summary workflow
  • gh-aw.md — Content Scanning section with full workflow
  • security.md — unpack coverage, SARIF/markdown output
  • governance.md — SARIF + step summary examples
  • cli-commands.md — new flags

apm-action (PR #14)

  • runAuditReport() now also writes markdown step summary wrapped in <details> to $GITHUB_STEP_SUMMARY
  • Best-effort (never fails the action)

CI golden path

- uses: microsoft/apm-action@v1
  with:
    commands: apm install
- run: apm audit -f sarif -o apm-audit.sarif
  if: always()
- run: apm audit -f markdown >> $GITHUB_STEP_SUMMARY
  if: always()
- uses: github/codeql-action/upload-sarif@v3
  if: always()
  with:
    sarif_file: apm-audit.sarif
    category: apm-audit

danielmeppiel and others added 4 commits March 16, 2026 22:53
Replace all apm audit --ci commands in docs with apm audit (which works
today via exit codes 0/1/2). All remaining --ci references are now
explicitly marked as planned/not yet available.

Files updated:
- integrations/ci-cd.md
- integrations/github-rulesets.md
- enterprise/governance.md
- enterprise/making-the-case.md
- enterprise/adoption-playbook.md
- reference/lockfile-spec.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Scan bundle files for hidden Unicode characters after extraction but
before deployment, matching the install command's pattern.

- Add security_warnings/security_critical fields to UnpackResult
- Add force parameter to unpack_bundle() for audit override
- Add --force flag to unpack_cmd CLI command
- Display security warnings/critical counts in CLI output
- Block deployment on critical findings unless --force is used
- Skip symlinks and handle binary files gracefully

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add machine-readable output formats to the standalone apm audit command:
- --format/-f: text (default), json (machine-readable), sarif (GitHub Code Scanning)
- --output/-o: write to file with auto-detection from extension (.sarif, .json)
- New security/audit_report.py module for SARIF 2.1.0 and JSON serialization
- ScanFinding maps 1:1 to SARIF fields (relative paths only, no content snippets)
- Incompatible with --strip/--dry-run (validated with error message)
- 16 new tests covering JSON, SARIF, format detection, and file writing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- security.md: add apm unpack to scanning coverage, document SARIF output
- ci-cd.md: add SARIF golden path workflow for Code Scanning integration
- gh-aw.md: add Content Scanning section explaining audit in gh-aw context
- CHANGELOG.md: add unpack scanning, SARIF output, and --ci doc fix entries

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

This PR hardens APM’s security posture by extending hidden-Unicode content scanning to apm unpack (pre-deploy) and by adding machine-readable apm audit outputs (JSON + SARIF) for CI and GitHub Code Scanning, alongside documentation updates to reflect current vs planned audit capabilities.

Changes:

  • Add hidden-Unicode scanning gate to apm unpack, with --force override and result counters.
  • Add apm audit --format {text,json,sarif} and --output for CI-friendly JSON/SARIF reporting.
  • Align docs and changelog around apm audit behavior and the planned (not yet available) apm audit --ci.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
uv.lock Bumps editable package version to 0.8.0.
src/apm_cli/bundle/unpacker.py Adds post-extract, pre-deploy content scanning and exposes counts on UnpackResult.
src/apm_cli/commands/pack.py Adds apm unpack --force plumbing and user-facing warnings on forced/warning deploys.
src/apm_cli/commands/audit.py Adds --format/--output, auto-detection, and routes to text vs JSON/SARIF output paths.
src/apm_cli/security/audit_report.py Implements JSON + SARIF (2.1.0) serialization utilities.
tests/unit/test_unpack_security.py New unit tests for unpack scanning behavior (clean/warn/critical/force/binary/symlink).
tests/unit/test_audit_report.py New unit tests covering JSON/SARIF serialization, format detection, and writing.
docs/src/content/docs/reference/lockfile-spec.md Updates CI guidance to reflect apm audit --ci as planned.
docs/src/content/docs/reference/cli-commands.md Documents apm audit -f/--format and -o/--output.
docs/src/content/docs/integrations/github-rulesets.md Reframes CI gating around current apm audit exit codes; marks --ci as planned.
docs/src/content/docs/integrations/gh-aw.md Adds content scanning section and SARIF workflow example.
docs/src/content/docs/integrations/ci-cd.md Adds SARIF “golden path” workflow and planned-note re: --ci.
docs/src/content/docs/enterprise/security.md Documents unpack scanning + SARIF/JSON output usage.
docs/src/content/docs/enterprise/making-the-case.md Updates messaging from planned --ci to current apm audit gating.
docs/src/content/docs/enterprise/governance.md Updates CI enforcement section and adds SARIF upload example.
docs/src/content/docs/enterprise/adoption-playbook.md Updates CI step to audit content issues with apm audit.
CHANGELOG.md Adds Unreleased entries for unpack scanning + audit reporting + doc drift fix.

Comment on lines +145 to +155
for rel_path in unique_files:
source_file = source_dir / rel_path
if source_file.is_file() and not source_file.is_symlink():
findings = scanner.scan_file(source_file)
if findings:
all_findings[rel_path] = findings

if all_findings:
flat = [f for ff in all_findings.values() for f in ff]
has_critical, counts = scanner.classify(flat)
security_critical = counts.get("critical", 0)
Comment on lines +167 to +171
f"Affected files:\n" + "\n".join(affected) + "\n\n"
"Next steps:\n"
" - Run: apm audit --file <file> to see details\n"
" - Run: apm unpack --force to deploy anyway "
"(not recommended)\n\n"
Comment on lines +47 to +57
items = []
for finding in all_findings:
items.append({
"severity": finding.severity,
"file": finding.file,
"line": finding.line,
"column": finding.column,
"codepoint": finding.codepoint,
"category": finding.category,
"description": finding.description,
})
danielmeppiel and others added 3 commits March 16, 2026 23:53
- Fix type annotation for deployed_files helper (dict[str, Union[str, bytes]])
- Use relative link in gh-aw docs for content scanning reference
- Add try/except guard for symlink creation in tests (platform compat)
- Add PR numbers and markdown format to CHANGELOG entries
- Fix error message to not reference temp path in unpacker

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add findings_to_markdown() for GFM output ()
- Wire markdown into audit.py --format choices + auto-detect .md
- Fix symlink bypass in unpack: skip symlinks during deploy
- Fix absolute paths in SARIF/JSON: normalize to relative
- Fix format validation order: resolve effective_format before check
- Fix detect_format_from_extension default: text instead of sarif

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…docs (#330)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel danielmeppiel changed the title feat: audit hardening — unpack scanning, SARIF/JSON output feat: audit hardening — unpack scanning, SARIF/JSON/Markdown output Mar 16, 2026
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.

Audit hardening: unpack scanning, SARIF/JSON output, apm-action wiring

2 participants