Skip to content

Remove attestation from App Security - #8692

Merged
jek merged 7 commits into
mainfrom
app-security/loosen-consistency-checks
Oct 1, 2026
Merged

jek merged 7 commits into
mainfrom
app-security/loosen-consistency-checks

Conversation

@jek

@jek jek commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

App Security attested that agent results matched the scanned source, using input hashing, fingerprints and source_scan_id/prompt_hash matching. That coupling made the flow brittle and hard to reason about, while the results are informational.

WHAT is this pull request doing?

Reports where an app stands right now, without comparing the deterministic and agent artifacts:

  • check writes deterministic-findings.json (was trace.json) and agent-checks.json (checks for the coding agent, was review.json) on every run, without prompting.
  • record (new) validates the agent's findings document from stdin and writes agent-findings.json
  • review (new, rough) prints both artifacts with their ages; the next PR in the stack replaces it.
  • clean (new) removes current and legacy artifacts.
  • submit (rough) stubbed. It uses upload schema version 0 so the server rejects it; the next PR in the stack replaces it.

New artifacts are durable against cli change: a generated agent-findings.json snapshots key check information, enabling review to continue to interpret results regardless of whether the check still exists in cli.

Removes attestation, input hashing, fingerprints, suppressions, and the compile and external paths.

This change is intended to land in / squash with the stack.

How to manually test your changes?

pnpm shopify app security check --path /path/to/app
pnpm shopify app security record --path /path/to/app < findings.json
pnpm shopify app security review --path /path/to/app
pnpm shopify app security clean --path /path/to/app

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes
  • I've considered analytics changes to measure impact
  • The change is user-facing — I've identified the correct bump type (patch for bug fixes · minor for new features · major for breaking changes) and added a changeset with pnpm changeset add

@jek
jek added this pull request to stack #8694 September 29, 2026 00:23
@github-actions github-actions Bot added the no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. label Sep 29, 2026
@jek
jek force-pushed the app-security/loosen-consistency-checks branch from c32ac30 to 424d4b9 Compare September 30, 2026 16:31
@jek
jek marked this pull request as ready for review September 30, 2026 19:54
@jek
jek requested review from a team as code owners September 30, 2026 19:54

@dmerand dmerand 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.

Tophat/smoke testing LGTM. No major blockers; per our discussion we'll get this through + focus on polish as a follow-up. I've just got a couple of notes from my review with agents.

[['Fix every error, then run', {command: recordCommand(commands)}, 'again.']],
[{title: 'Errors', body: {list: {items: errors}}}],
)
error.details = {errors}

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.

Can we redact validation errors before adding them to the error banner and details.errors? An invalid line, file, or check_id can contain a Shopify token. record copies that value into both terminal and --json output. I reproduced this with a synthetic token. The previous findings file stayed unchanged, but the error displayed the token. Please add tests for both output modes.

export async function writeAgentFindings(appRoot: string, artifact: AgentFindingsArtifact): Promise<string> {
const paths = appSecurityArtifactPaths(appRoot)
await ensureArtifactDirectory(appRoot, paths.artifactDirectory)
await writeAtomicArtifact(paths.agentFindingsPath, encodeArtifact(artifact))

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.

Can we ensure record writes only artifacts that review can read? A valid 4,989,926-byte input produced a 5,085,618-byte agent-findings.json after the check snapshots and formatting. record returned success, but the 5 MB reader rejected the file as invalid. Please check the encoded size before replacing the old file, or adjust the bounded read limit. A record-to-review test near the limit would catch this.

): string {
const commandLine = formatCommandLine(action, shell)
if (!action.stdinPlaceholder) return commandLine
if (shell === 'powershell') return `Get-Content -Raw ${action.stdinPlaceholder} | ${commandLine}`

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.

Could we read the findings file as UTF-8 in the PowerShell command? Windows PowerShell 5.1 defaults to the active ANSI code page for BOM-less files. A UTF-8 findings file with a path like app/café.ts can remain valid JSON but record the wrong path. The instructions' $OutputEncoding note only affects the later pipe; it cannot repair the file read. Please use -Encoding UTF8 (or another UTF-8-safe read) and test a BOM-less UTF-8 file through PowerShell 5.1 into record. I checked the generated command and docs, but did not run PowerShell 5.1 here.

@jek
jek force-pushed the app-security/loosen-consistency-checks branch from 424d4b9 to f86890c Compare October 1, 2026 02:01

@dmerand dmerand 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.

We can fix-forward the existing comments.

jek and others added 7 commits October 1, 2026 14:26
Nothing in the check pipeline produces external findings, so
mergeExternalFindings and validateExternalFinding were only reachable
from their own tests. Remove the module and those tests before
reworking the trace path, so later commits don't carry dead code.

Co-authored-by: AI <noreply@pi.dev>
The trace carried fingerprints, input/result hashes, an attestation digest and
merged agent findings so agent results could be compiled and verified. Drop all
of that: the compile path (check --findings, exit code 2, the "existing work"
guard), suppressions, and the hashing. The trace is now the deterministic scan
only, and the submission payload is trimmed to match.

Co-authored-by: AI <noreply@pi.dev>
The trace was a validated, hash-carrying document. deterministic-findings.json is the plain
deterministic scan: only the schema version and findings array are checked
on read, and submit re-checks it for unredacted secrets. The check output,
JSON output and submission payload now come from deterministic-findings.json (upload schema
version 0), and the trace-only fields (required, guidance, implementations,
coverage.complete) are dropped from the scan model.

Co-authored-by: AI <noreply@pi.dev>
The review pack carried a findings-era name and a bare security_version.
Rename it to agent checks (agent-checks.json) with an engine {name, version}
block, and have `check --json` return agent_checks_path instead of embedding
the whole pack. Update the check output and instructions wording, and take
the prompt fixes for SQL injection, XSS and unsafe innerHTML so they no
longer refer to a review pack or prompt hashes.

Co-authored-by: AI <noreply@pi.dev>
Agents now submit their investigation results through a new hidden
`app security record` command. It reads one findings document from
stdin, validates it all-or-nothing in the engine (redacting agent text
and snapshotting check metadata), and replaces agent-findings.json.
The check output, instructions, and agent-checks text now point agents
at `record`.

Co-authored-by: AI <noreply@pi.dev>
`check --clean` mixed two jobs: scanning and deleting local review
work. Add a dedicated `app security clean` command that removes every
current and legacy artifact (scan, agent checks, agent findings,
submission, trace/review/findings.json) without asking, and drop the
flag. Check now only replaces deterministic-findings.json and agent-checks.json, so it
is always safe to run again.

Co-authored-by: AI <noreply@pi.dev>
Add a hidden `app security review` command that prints the stored scan
and recorded agent findings, each with its path and age. The two files
are shown as stored, without being compared with each other or with the
current source. The instructions and command output now point to it.

Co-authored-by: AI <noreply@pi.dev>
@jek
jek force-pushed the app-security/loosen-consistency-checks branch from f86890c to 245343a Compare October 1, 2026 21:36
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

⚠️ Potential Breaking Changes Detected

This PR contains changes that may break the existing contract.

@shopify/dev_experience — this PR contains breaking changes that require coordination for the next major release.

🏳️ Removed Flags

The following flags were removed from existing commands:

Command Flag
app:security:check --clean
app:security:check --findings

🔧 Removed Environment Variables

The following env vars are no longer referenced in command flags:

Env Var Previously Used By
SHOPIFY_FLAG_APP_SECURITY_FINDINGS app:security:check --findings

@jek
jek added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit 121eb91 Oct 1, 2026
29 of 30 checks passed
@jek
jek deleted the app-security/loosen-consistency-checks branch October 1, 2026 22:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants