Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/app': patch
---

Check for Dependabot or Renovate configuration at the Git repository root when `shopify app security check` scans an app below it
6 changes: 6 additions & 0 deletions .changeset/app-security-flag-descriptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@shopify/app': patch
'@shopify/cli': patch
---

Clarify the `--blocking` and `--skip-instructions` help text for `shopify app security`
6 changes: 6 additions & 0 deletions .changeset/app-security-monorepo-lockfiles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@shopify/app': patch
'@shopify/cli': patch
---

Skip lockfiles in every `shopify app security check` scan directory, so a monorepo root lockfile no longer leaves the secret check unresolved
5 changes: 5 additions & 0 deletions .changeset/app-security-react-router-roots.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/app': patch
---

Detect React Router app code outside the app directory, such as in `--include-dir` or web directories, in `shopify app security check`
6 changes: 6 additions & 0 deletions .changeset/app-security-unresolved-calibration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@shopify/app': patch
'@shopify/cli': patch
---

Stop app security agent checks from leaving the React Router app template's metafield, authorization and frame-ancestors checks unresolved
10 changes: 5 additions & 5 deletions docs-shopify.dev/generated/generated_docs_data_v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -3361,7 +3361,7 @@
"syntaxKind": "PropertySignature",
"name": "--blocking <value>",
"value": "string",
"description": "The minimum finding severity that causes a non-zero exit code.",
"description": "The minimum finding severity that causes a non-zero exit code: high, medium, or low. Defaults to none, which never fails on findings.",
"isOptional": true,
"environmentValue": "SHOPIFY_FLAG_APP_SECURITY_BLOCKING"
},
Expand Down Expand Up @@ -3449,7 +3449,7 @@
"syntaxKind": "PropertySignature",
"name": "--skip-instructions",
"value": "''",
"description": "Don't offer to show coding-agent instructions.",
"description": "Don't offer the coding-agent instructions after the scan. Use it when you want only the deterministic scan results.",
"isOptional": true,
"environmentValue": "SHOPIFY_FLAG_APP_SECURITY_SKIP_INSTRUCTIONS"
},
Expand Down Expand Up @@ -3490,7 +3490,7 @@
"environmentValue": "SHOPIFY_FLAG_APP_CONFIG"
}
],
"value": "export interface appsecuritycheck {\n /**\n * The minimum finding severity that causes a non-zero exit code.\n * @environment SHOPIFY_FLAG_APP_SECURITY_BLOCKING\n */\n '--blocking <value>'?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id <value>'?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config <value>'?: string\n\n /**\n * Skip paths that match this glob, relative to the working directory. Repeat the flag to add globs. The selected app configuration file can't be excluded.\n *\n */\n '--exclude <value>'?: string\n\n /**\n * Also scan this directory, relative to the working directory. Repeat the flag to add directories. Use it for code that lives outside the app directory, such as a backend or a shared library.\n *\n */\n '--include-dir <value>'?: string\n\n /**\n * Print the command's JSON schemas.\n * @environment SHOPIFY_FLAG_JSON_SCHEMA\n */\n '--json-schema'?: ''\n\n /**\n * Print the files the check would gather, one path per line, and stop. Nothing is scanned, no results are written, and nothing is prompted for.\n * @environment SHOPIFY_FLAG_LIST_FILES\n */\n '--list-files'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Turn off Git ignore rules for every scanned directory, so files that Git ignores are scanned too. Files that Git tracks are always scanned.\n * @environment SHOPIFY_FLAG_NO_GIT_IGNORE\n */\n '--no-git-ignore'?: ''\n\n /**\n * Disable interactive prompts and browser authentication.\n * @environment SHOPIFY_FLAG_NO_INPUT\n */\n '--no-input'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path <value>'?: string\n\n /**\n * Don't offer to show coding-agent instructions.\n * @environment SHOPIFY_FLAG_APP_SECURITY_SKIP_INSTRUCTIONS\n */\n '--skip-instructions'?: ''\n\n /**\n * Increase the verbosity of the output. May include sensitive data.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Scan --path as an app with no app configuration file. Config checks are skipped. Requires --client-id.\n * @environment SHOPIFY_FLAG_WITHOUT_APP_CONFIG\n */\n '--without-app-config'?: ''\n\n /**\n * Print coding-agent instructions without prompting.\n * @environment SHOPIFY_FLAG_YES\n */\n '--yes'?: ''\n}"
"value": "export interface appsecuritycheck {\n /**\n * The minimum finding severity that causes a non-zero exit code: high, medium, or low. Defaults to none, which never fails on findings.\n * @environment SHOPIFY_FLAG_APP_SECURITY_BLOCKING\n */\n '--blocking <value>'?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id <value>'?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config <value>'?: string\n\n /**\n * Skip paths that match this glob, relative to the working directory. Repeat the flag to add globs. The selected app configuration file can't be excluded.\n *\n */\n '--exclude <value>'?: string\n\n /**\n * Also scan this directory, relative to the working directory. Repeat the flag to add directories. Use it for code that lives outside the app directory, such as a backend or a shared library.\n *\n */\n '--include-dir <value>'?: string\n\n /**\n * Print the command's JSON schemas.\n * @environment SHOPIFY_FLAG_JSON_SCHEMA\n */\n '--json-schema'?: ''\n\n /**\n * Print the files the check would gather, one path per line, and stop. Nothing is scanned, no results are written, and nothing is prompted for.\n * @environment SHOPIFY_FLAG_LIST_FILES\n */\n '--list-files'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Turn off Git ignore rules for every scanned directory, so files that Git ignores are scanned too. Files that Git tracks are always scanned.\n * @environment SHOPIFY_FLAG_NO_GIT_IGNORE\n */\n '--no-git-ignore'?: ''\n\n /**\n * Disable interactive prompts and browser authentication.\n * @environment SHOPIFY_FLAG_NO_INPUT\n */\n '--no-input'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path <value>'?: string\n\n /**\n * Don't offer the coding-agent instructions after the scan. Use it when you want only the deterministic scan results.\n * @environment SHOPIFY_FLAG_APP_SECURITY_SKIP_INSTRUCTIONS\n */\n '--skip-instructions'?: ''\n\n /**\n * Increase the verbosity of the output. May include sensitive data.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Scan --path as an app with no app configuration file. Config checks are skipped. Requires --client-id.\n * @environment SHOPIFY_FLAG_WITHOUT_APP_CONFIG\n */\n '--without-app-config'?: ''\n\n /**\n * Print coding-agent instructions without prompting.\n * @environment SHOPIFY_FLAG_YES\n */\n '--yes'?: ''\n}"
}
},
"appsecurityclean": {
Expand Down Expand Up @@ -3780,7 +3780,7 @@
"syntaxKind": "PropertySignature",
"name": "--blocking <value>",
"value": "string",
"description": "The minimum finding severity that causes a non-zero exit code.",
"description": "The minimum finding severity that causes a non-zero exit code: high, medium, or low. Defaults to none, which never fails on findings.",
"isOptional": true,
"environmentValue": "SHOPIFY_FLAG_APP_SECURITY_BLOCKING"
},
Expand Down Expand Up @@ -3866,7 +3866,7 @@
"environmentValue": "SHOPIFY_FLAG_APP_CONFIG"
}
],
"value": "export interface appsecurityreview {\n /**\n * The minimum finding severity that causes a non-zero exit code.\n * @environment SHOPIFY_FLAG_APP_SECURITY_BLOCKING\n */\n '--blocking <value>'?: string\n\n /**\n * Show only this check. Repeat the flag to show several checks.\n * @environment SHOPIFY_FLAG_CHECK_ID\n */\n '--check-id <value>'?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id <value>'?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config <value>'?: string\n\n /**\n * Print the command's JSON schemas.\n * @environment SHOPIFY_FLAG_JSON_SCHEMA\n */\n '--json-schema'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Disable interactive prompts and browser authentication.\n * @environment SHOPIFY_FLAG_NO_INPUT\n */\n '--no-input'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path <value>'?: string\n\n /**\n * Increase the verbosity of the output. May include sensitive data.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Scan --path as an app with no app configuration file. Config checks are skipped. Requires --client-id.\n * @environment SHOPIFY_FLAG_WITHOUT_APP_CONFIG\n */\n '--without-app-config'?: ''\n}"
"value": "export interface appsecurityreview {\n /**\n * The minimum finding severity that causes a non-zero exit code: high, medium, or low. Defaults to none, which never fails on findings.\n * @environment SHOPIFY_FLAG_APP_SECURITY_BLOCKING\n */\n '--blocking <value>'?: string\n\n /**\n * Show only this check. Repeat the flag to show several checks.\n * @environment SHOPIFY_FLAG_CHECK_ID\n */\n '--check-id <value>'?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id <value>'?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config <value>'?: string\n\n /**\n * Print the command's JSON schemas.\n * @environment SHOPIFY_FLAG_JSON_SCHEMA\n */\n '--json-schema'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Disable interactive prompts and browser authentication.\n * @environment SHOPIFY_FLAG_NO_INPUT\n */\n '--no-input'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path <value>'?: string\n\n /**\n * Increase the verbosity of the output. May include sensitive data.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Scan --path as an app with no app configuration file. Config checks are skipped. Requires --client-id.\n * @environment SHOPIFY_FLAG_WITHOUT_APP_CONFIG\n */\n '--without-app-config'?: ''\n}"
}
},
"appsubscriptionmigrationscancel": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const blockingLevels: AppSecurityBlockingLevel[] = ['high', 'medium', 'low', 'no
*/
export const appSecurityBlockingFlag = {
blocking: Flags.custom<AppSecurityBlockingLevel>({
description: 'The minimum finding severity that causes a non-zero exit code.',
description:
'The minimum finding severity that causes a non-zero exit code: high, medium, or low. Defaults to none, which never fails on findings.',
options: blockingLevels,
default: 'none',
env: 'SHOPIFY_FLAG_APP_SECURITY_BLOCKING',
Expand Down
4 changes: 3 additions & 1 deletion packages/app/src/cli/commands/app/security/check.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@ describe('app security check command', () => {

test('describes the artifacts it writes and how agent results are recorded', () => {
expect(SecurityCheck.flags.yes.description).toBe('Print coding-agent instructions without prompting.')
expect(SecurityCheck.flags['skip-instructions'].description).toBe("Don't offer to show coding-agent instructions.")
expect(SecurityCheck.flags['skip-instructions'].description).toBe(
"Don't offer the coding-agent instructions after the scan. Use it when you want only the deterministic scan results.",
)
expect(SecurityCheck.flags.yes.exclusive).toEqual(['skip-instructions'])
expect(SecurityCheck.flags['skip-instructions'].exclusive).toEqual(['yes'])
expect(SecurityCheck.summary).toContain('deterministic-findings.json')
Expand Down
3 changes: 2 additions & 1 deletion packages/app/src/cli/commands/app/security/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ In interactive terminals, the command offers to copy the coding-agent instructio
env: 'SHOPIFY_FLAG_YES',
}),
'skip-instructions': Flags.boolean({
description: "Don't offer to show coding-agent instructions.",
description:
"Don't offer the coding-agent instructions after the scan. Use it when you want only the deterministic scan results.",
default: false,
exclusive: ['yes'],
env: 'SHOPIFY_FLAG_APP_SECURITY_SKIP_INSTRUCTIONS',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ For each check:
5. Keep the check `id` and `version` exactly as they appear in {{AGENT_CHECKS_PATH}}.
6. Include concise evidence citations. Never include a detected secret value or unnecessary personal data.

A check with no verified issue must not produce a fabricated finding. If you cannot establish exploitability or affected authority, record the check as `unresolved` with a reason instead.
A check with no verified issue must not produce a fabricated finding. Choose the status from what you were able to investigate, not from whether you can prove a negative:

- `executed`: you traced the paths the check directs you to and found no concrete issue. This includes code that follows the safe pattern the check or its `docs_url` describes. A candidate is ruled out when the code establishes the boundary the check asks about, even if you can't rule out hypothetical policies or requirements that the repository doesn't define.
- `unresolved`: you couldn't complete the investigation, for example because required code was unreadable, out of scope, or outside the repository and you couldn't inspect it, or you found a specific candidate whose boundary you could neither establish nor show to be missing. Name the candidate's file and line, or the missing input, in the reason.

### 4. Write one findings document

Expand Down Expand Up @@ -88,7 +91,7 @@ Write a single JSON document that covers every check you ran:
- `status` is one of:
- `executed`: you investigated the check, whether or not it produced findings.
- `not_applicable`: the capability the check covers is absent. It can't have findings.
- `unresolved`: you couldn't finish the check or prove the issue. An unresolved check didn't pass; never describe it as passing.
- `unresolved`: you couldn't complete the investigation, or you named a specific candidate whose boundary is still unclear. An unresolved check didn't pass; never describe it as passing.
- `not_applicable` and `unresolved` require a `reason` with a short `code` and a `message`.
- Each finding needs `file`, `line` (1 or greater), `message`, and at least one `evidence` item with `file`, `line`, and `quote`.
- Optional finding fields: `snippet`, `confidence` (`high`, `medium`, or `low`), `reasoning`, and `suppression` (`{"justification": "..."}`).
Expand Down
Loading
Loading