From ba84763eb5b723856a75c05979acda2eb9cd8e5d Mon Sep 17 00:00:00 2001 From: Nick Wesselman <27013789+nickwesselman@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:56:23 -0400 Subject: [PATCH 1/2] Unhide shopify app security commands Co-Authored-By: Claude Opus 5.5 (1M context) --- .changeset/unhide-app-security-commands.md | 6 + .../generated/generated_docs_data_v2.json | 520 ++++++++++++++++++ .../cli/commands/app/security/check.test.ts | 4 +- .../src/cli/commands/app/security/check.ts | 2 - .../cli/commands/app/security/clean.test.ts | 4 +- .../src/cli/commands/app/security/clean.ts | 2 - .../app/security/instructions.test.ts | 4 +- .../cli/commands/app/security/instructions.ts | 2 - .../cli/commands/app/security/record.test.ts | 4 +- .../src/cli/commands/app/security/record.ts | 2 - .../cli/commands/app/security/review.test.ts | 4 +- .../src/cli/commands/app/security/review.ts | 2 - packages/cli/README.md | 356 ++++++++++++ packages/cli/oclif.manifest.json | 5 - packages/cli/package.json | 3 +- packages/e2e/data/snapshots/commands.txt | 6 + 16 files changed, 899 insertions(+), 27 deletions(-) create mode 100644 .changeset/unhide-app-security-commands.md diff --git a/.changeset/unhide-app-security-commands.md b/.changeset/unhide-app-security-commands.md new file mode 100644 index 00000000000..150159a1097 --- /dev/null +++ b/.changeset/unhide-app-security-commands.md @@ -0,0 +1,6 @@ +--- +'@shopify/app': minor +'@shopify/cli': minor +--- + +Add `shopify app security` commands to check an app's source code for Shopify-specific security issues. `check` runs deterministic rules and generates checks for your coding agent to investigate, `record` saves the agent's findings, `review` shows the combined results, `instructions` prints the workflow for a coding agent, and `clean` removes local results. diff --git a/docs-shopify.dev/generated/generated_docs_data_v2.json b/docs-shopify.dev/generated/generated_docs_data_v2.json index ba48244cff6..af6f199146d 100644 --- a/docs-shopify.dev/generated/generated_docs_data_v2.json +++ b/docs-shopify.dev/generated/generated_docs_data_v2.json @@ -3349,6 +3349,526 @@ "value": "export interface apprelease {\n /**\n * Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates. Required in non-interactive environments unless --allow-updates is provided.\n * @environment SHOPIFY_FLAG_ALLOW_DELETES\n */\n '--allow-deletes'?: ''\n\n /**\n * Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments. Required in non-interactive environments unless --allow-deletes is provided.\n * @environment SHOPIFY_FLAG_ALLOW_UPDATES\n */\n '--allow-updates'?: ''\n\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: 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 '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output. May include sensitive data.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * The name of the app version to release.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version ': string\n}" } }, + "appsecuritycheck": { + "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts": { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "name": "appsecuritycheck", + "description": "The following flags are available for the `app security check` command:", + "isPublicDocs": true, + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--blocking ", + "value": "string", + "description": "The minimum finding severity that causes a non-zero exit code.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_SECURITY_BLOCKING" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--client-id ", + "value": "string", + "description": "The Client ID of your app.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_CLIENT_ID" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--exclude ", + "value": "string", + "description": "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.", + "isOptional": true + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--include-dir ", + "value": "string", + "description": "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.", + "isOptional": true + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--json-schema", + "value": "''", + "description": "Print the command's JSON schemas.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON_SCHEMA" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--list-files", + "value": "''", + "description": "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.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_LIST_FILES" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "''", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-git-ignore", + "value": "''", + "description": "Turn off Git ignore rules for every scanned directory, so files that Git ignores are scanned too. Files that Git tracks are always scanned.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_GIT_IGNORE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-input", + "value": "''", + "description": "Disable interactive prompts and browser authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_INPUT" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--path ", + "value": "string", + "description": "The path to your app directory.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_PATH" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--skip-instructions", + "value": "''", + "description": "Don't offer to show coding-agent instructions.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_SECURITY_SKIP_INSTRUCTIONS" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output. May include sensitive data.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--without-app-config", + "value": "''", + "description": "Scan --path as an app with no app configuration file. Config checks are skipped. Requires --client-id.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_WITHOUT_APP_CONFIG" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--yes", + "value": "''", + "description": "Print coding-agent instructions without prompting.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_YES" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-c, --config ", + "value": "string", + "description": "The name of the app configuration.", + "isOptional": true, + "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 '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: 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 '?: 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 '?: 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 '?: 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}" + } + }, + "appsecurityclean": { + "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts": { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "name": "appsecurityclean", + "description": "The following flags are available for the `app security clean` command:", + "isPublicDocs": true, + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--all", + "value": "''", + "description": "Delete every results directory under .shopify/app-security/, not only the selected one.", + "isOptional": true + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--client-id ", + "value": "string", + "description": "The Client ID of your app.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_CLIENT_ID" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--json-schema", + "value": "''", + "description": "Print the command's JSON schemas.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON_SCHEMA" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "''", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-input", + "value": "''", + "description": "Disable interactive prompts and browser authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_INPUT" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--path ", + "value": "string", + "description": "The path to your app directory.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_PATH" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output. May include sensitive data.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--without-app-config", + "value": "''", + "description": "Scan --path as an app with no app configuration file. Config checks are skipped. Requires --client-id.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_WITHOUT_APP_CONFIG" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-c, --config ", + "value": "string", + "description": "The name of the app configuration.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" + } + ], + "value": "export interface appsecurityclean {\n /**\n * Delete every results directory under .shopify/app-security/, not only the selected one.\n *\n */\n '--all'?: ''\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: 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 '?: 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}" + } + }, + "appsecurityinstructions": { + "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts": { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "name": "appsecurityinstructions", + "description": "The following flags are available for the `app security instructions` command:", + "isPublicDocs": true, + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--client-id ", + "value": "string", + "description": "The Client ID of your app.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_CLIENT_ID" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--copy", + "value": "''", + "description": "Copy the instructions to the clipboard instead of printing them.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_SECURITY_INSTRUCTIONS_COPY" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--json-schema", + "value": "''", + "description": "Print the command's JSON schemas.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON_SCHEMA" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "''", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-input", + "value": "''", + "description": "Disable interactive prompts and browser authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_INPUT" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--path ", + "value": "string", + "description": "The path to your app directory.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_PATH" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output. May include sensitive data.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--without-app-config", + "value": "''", + "description": "Scan --path as an app with no app configuration file. Config checks are skipped. Requires --client-id.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_WITHOUT_APP_CONFIG" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--write ", + "value": "string", + "description": "Write the instructions to a file instead of printing them.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_SECURITY_INSTRUCTIONS_WRITE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-instructions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-c, --config ", + "value": "string", + "description": "The name of the app configuration.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" + } + ], + "value": "export interface appsecurityinstructions {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Copy the instructions to the clipboard instead of printing them.\n * @environment SHOPIFY_FLAG_APP_SECURITY_INSTRUCTIONS_COPY\n */\n '--copy'?: ''\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 '?: 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\n /**\n * Write the instructions to a file instead of printing them.\n * @environment SHOPIFY_FLAG_APP_SECURITY_INSTRUCTIONS_WRITE\n */\n '--write '?: string\n}" + } + }, + "appsecurityrecord": { + "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts": { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts", + "name": "appsecurityrecord", + "description": "The following flags are available for the `app security record` command:", + "isPublicDocs": true, + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--client-id ", + "value": "string", + "description": "The Client ID of your app.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_CLIENT_ID" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--json-schema", + "value": "''", + "description": "Print the command's JSON schemas.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON_SCHEMA" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "''", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-input", + "value": "''", + "description": "Disable interactive prompts and browser authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_INPUT" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--path ", + "value": "string", + "description": "The path to your app directory.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_PATH" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output. May include sensitive data.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--without-app-config", + "value": "''", + "description": "Scan --path as an app with no app configuration file. Config checks are skipped. Requires --client-id.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_WITHOUT_APP_CONFIG" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-record.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-c, --config ", + "value": "string", + "description": "The name of the app configuration.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" + } + ], + "value": "export interface appsecurityrecord {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: 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 '?: 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}" + } + }, + "appsecurityreview": { + "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts": { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "name": "appsecurityreview", + "description": "The following flags are available for the `app security review` command:", + "isPublicDocs": true, + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--blocking ", + "value": "string", + "description": "The minimum finding severity that causes a non-zero exit code.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_SECURITY_BLOCKING" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--check-id ", + "value": "string", + "description": "Show only this check. Repeat the flag to show several checks.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_CHECK_ID" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--client-id ", + "value": "string", + "description": "The Client ID of your app.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_CLIENT_ID" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--json-schema", + "value": "''", + "description": "Print the command's JSON schemas.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON_SCHEMA" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "''", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-input", + "value": "''", + "description": "Disable interactive prompts and browser authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_INPUT" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--path ", + "value": "string", + "description": "The path to your app directory.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_PATH" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output. May include sensitive data.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--without-app-config", + "value": "''", + "description": "Scan --path as an app with no app configuration file. Config checks are skipped. Requires --client-id.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_WITHOUT_APP_CONFIG" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-security-review.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-c, --config ", + "value": "string", + "description": "The name of the app configuration.", + "isOptional": true, + "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 '?: 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 '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: 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 '?: 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": { "docs-shopify.dev/commands/interfaces/app-subscription-migrations-cancel.interface.ts": { "filePath": "docs-shopify.dev/commands/interfaces/app-subscription-migrations-cancel.interface.ts", diff --git a/packages/app/src/cli/commands/app/security/check.test.ts b/packages/app/src/cli/commands/app/security/check.test.ts index 0382577413a..0e744e1ad2b 100644 --- a/packages/app/src/cli/commands/app/security/check.test.ts +++ b/packages/app/src/cli/commands/app/security/check.test.ts @@ -11,8 +11,8 @@ import {describe, expect, test, vi} from 'vitest' vi.mock('../../../services/security-check.js') describe('app security check command', () => { - test('is hidden and does not require linked app context', () => { - expect(SecurityCheck.hidden).toBe(true) + test('is visible and does not require linked app context', () => { + expect(SecurityCheck.hidden).toBeFalsy() expect(SecurityCheck.prototype).toBeInstanceOf(BaseCommand) expect(SecurityCheck.prototype).not.toBeInstanceOf(AppLinkedCommand) expect(SecurityCheck.flags.path).toBe(appFlags.path) diff --git a/packages/app/src/cli/commands/app/security/check.ts b/packages/app/src/cli/commands/app/security/check.ts index 05f8bbae971..22e5a0405b4 100644 --- a/packages/app/src/cli/commands/app/security/check.ts +++ b/packages/app/src/cli/commands/app/security/check.ts @@ -6,8 +6,6 @@ import BaseCommand from '@shopify/cli-kit/node/base-command' import {globalFlags} from '@shopify/cli-kit/node/cli' export default class SecurityCheck extends BaseCommand { - static hidden = true - static summary = 'Check an app for Shopify-specific security issues and write deterministic-findings.json and agent-checks.json.' diff --git a/packages/app/src/cli/commands/app/security/clean.test.ts b/packages/app/src/cli/commands/app/security/clean.test.ts index 73511cb5850..b2fe653e45a 100644 --- a/packages/app/src/cli/commands/app/security/clean.test.ts +++ b/packages/app/src/cli/commands/app/security/clean.test.ts @@ -75,8 +75,8 @@ function cleanedResult(appDirectory: string): SecurityCleanResult { } describe('app security clean command', () => { - test('is hidden and does not require linked app context', () => { - expect(SecurityClean.hidden).toBe(true) + test('is visible and does not require linked app context', () => { + expect(SecurityClean.hidden).toBeFalsy() expect(SecurityClean.prototype).toBeInstanceOf(BaseCommand) expect(SecurityClean.prototype).not.toBeInstanceOf(AppLinkedCommand) expect(SecurityClean.flags).not.toHaveProperty('json') diff --git a/packages/app/src/cli/commands/app/security/clean.ts b/packages/app/src/cli/commands/app/security/clean.ts index e33b5219127..10207761c1a 100644 --- a/packages/app/src/cli/commands/app/security/clean.ts +++ b/packages/app/src/cli/commands/app/security/clean.ts @@ -7,8 +7,6 @@ import BaseCommand from '@shopify/cli-kit/node/base-command' import {globalFlags} from '@shopify/cli-kit/node/cli' export default class SecurityClean extends BaseCommand { - static hidden = true - static summary = 'Remove local app security check results.' static descriptionWithMarkdown = `Deletes the results directory, \`.shopify/app-security//\`, without asking. The results key is \`--client-id\` when you pass it, and otherwise the name of the app configuration file without \`.toml\`. Other results directories are left alone. Prints each removed path. diff --git a/packages/app/src/cli/commands/app/security/instructions.test.ts b/packages/app/src/cli/commands/app/security/instructions.test.ts index abb94632476..ce35ae77213 100644 --- a/packages/app/src/cli/commands/app/security/instructions.test.ts +++ b/packages/app/src/cli/commands/app/security/instructions.test.ts @@ -65,8 +65,8 @@ function configSelection(appDirectory: string, configFileName: string): AppSecur } describe('app security instructions command', () => { - test('is hidden and does not require linked app context', () => { - expect(SecurityInstructions.hidden).toBe(true) + test('is visible and does not require linked app context', () => { + expect(SecurityInstructions.hidden).toBeFalsy() expect(SecurityInstructions.prototype).toBeInstanceOf(BaseCommand) expect(SecurityInstructions.prototype).not.toBeInstanceOf(AppLinkedCommand) expect(SecurityInstructions.args).not.toHaveProperty('directory') diff --git a/packages/app/src/cli/commands/app/security/instructions.ts b/packages/app/src/cli/commands/app/security/instructions.ts index f37e0d2ed93..6fe6ebe3287 100644 --- a/packages/app/src/cli/commands/app/security/instructions.ts +++ b/packages/app/src/cli/commands/app/security/instructions.ts @@ -9,8 +9,6 @@ import {globalFlags} from '@shopify/cli-kit/node/cli' import {resolvePath} from '@shopify/cli-kit/node/path' export default class SecurityInstructions extends BaseCommand { - static hidden = true - static summary = 'Provide app security check instructions to a coding agent.' static descriptionWithMarkdown = `Prints the complete workflow that a coding agent should follow to review app security check results. diff --git a/packages/app/src/cli/commands/app/security/record.test.ts b/packages/app/src/cli/commands/app/security/record.test.ts index 6a0ce5430e4..2d8ec4ccdec 100644 --- a/packages/app/src/cli/commands/app/security/record.test.ts +++ b/packages/app/src/cli/commands/app/security/record.test.ts @@ -66,8 +66,8 @@ function recordedResult(appRoot: string) { } describe('app security record command', () => { - test('is hidden and does not require linked app context', () => { - expect(SecurityRecord.hidden).toBe(true) + test('is visible and does not require linked app context', () => { + expect(SecurityRecord.hidden).toBeFalsy() expect(SecurityRecord.prototype).toBeInstanceOf(BaseCommand) expect(SecurityRecord.prototype).not.toBeInstanceOf(AppLinkedCommand) expect(SecurityRecord.flags).not.toHaveProperty('json') diff --git a/packages/app/src/cli/commands/app/security/record.ts b/packages/app/src/cli/commands/app/security/record.ts index fff1061f279..73645b7318d 100644 --- a/packages/app/src/cli/commands/app/security/record.ts +++ b/packages/app/src/cli/commands/app/security/record.ts @@ -6,8 +6,6 @@ import BaseCommand from '@shopify/cli-kit/node/base-command' import {globalFlags} from '@shopify/cli-kit/node/cli' export default class SecurityRecord extends BaseCommand { - static hidden = true - static summary = 'Record agent findings from an app security check.' static descriptionWithMarkdown = `Reads a coding agent's complete findings document from stdin, validates it, and replaces \`agent-findings.json\` in the results directory, \`.shopify/app-security//\`. The results key is \`--client-id\` when you pass it, and otherwise the name of the app configuration file without \`.toml\`. \`--client-id\` is checked against your Shopify account before anything is read, so it needs you to be logged in. diff --git a/packages/app/src/cli/commands/app/security/review.test.ts b/packages/app/src/cli/commands/app/security/review.test.ts index cf3af88c981..8e320098e96 100644 --- a/packages/app/src/cli/commands/app/security/review.test.ts +++ b/packages/app/src/cli/commands/app/security/review.test.ts @@ -10,8 +10,8 @@ import {describe, expect, test, vi} from 'vitest' vi.mock('../../../services/security-review.js') describe('app security review command', () => { - test('is hidden and does not require linked app context', () => { - expect(SecurityReview.hidden).toBe(true) + test('is visible and does not require linked app context', () => { + expect(SecurityReview.hidden).toBeFalsy() expect(SecurityReview.prototype).toBeInstanceOf(BaseCommand) expect(SecurityReview.prototype).not.toBeInstanceOf(AppLinkedCommand) expect(SecurityReview.flags).not.toHaveProperty('json') diff --git a/packages/app/src/cli/commands/app/security/review.ts b/packages/app/src/cli/commands/app/security/review.ts index 06c26e0b598..ab878717c8d 100644 --- a/packages/app/src/cli/commands/app/security/review.ts +++ b/packages/app/src/cli/commands/app/security/review.ts @@ -6,8 +6,6 @@ import BaseCommand from '@shopify/cli-kit/node/base-command' import {globalFlags} from '@shopify/cli-kit/node/cli' export default class SecurityReview extends BaseCommand { - static hidden = true - static summary = 'Show the combined app security check results.' static descriptionWithMarkdown = `Combines the deterministic results (\`deterministic-findings.json\`, written by \`shopify app security check\`) with the recorded agent results (\`agent-findings.json\`, written by \`shopify app security record\`) and shows one view of every check: its findings, status and source. Both files are in the results directory, \`.shopify/app-security//\`. \`--client-id\` is checked against your Shopify account before any results are read, so it needs you to be logged in. diff --git a/packages/cli/README.md b/packages/cli/README.md index b3624194936..997b0a3b74e 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -29,6 +29,11 @@ * [`shopify app logs`](#shopify-app-logs) * [`shopify app logs sources`](#shopify-app-logs-sources) * [`shopify app release --version `](#shopify-app-release---version-version) +* [`shopify app security check`](#shopify-app-security-check) +* [`shopify app security clean`](#shopify-app-security-clean) +* [`shopify app security instructions`](#shopify-app-security-instructions) +* [`shopify app security record`](#shopify-app-security-record) +* [`shopify app security review`](#shopify-app-security-review) * [`shopify app subscription-migrations cancel`](#shopify-app-subscription-migrations-cancel) * [`shopify app subscription-migrations list`](#shopify-app-subscription-migrations-list) * [`shopify app subscription-migrations schedule`](#shopify-app-subscription-migrations-schedule) @@ -3046,6 +3051,357 @@ DESCRIPTION Releases an existing app version. Pass the name of the version that you want to release using the `--version` flag. ``` +## `shopify app security check` + +Check an app for Shopify-specific security issues and write deterministic-findings.json and agent-checks.json. + +``` +USAGE + $ shopify app security check [--exclude ...] [--include-dir ...] [--json-schema] [--list-files | --yes | + --skip-instructions | --blocking high|medium|low|none] [--no-color] [--no-git-ignore] [--no-input] [--path ] + [--verbose] [--without-app-config [--client-id | -c ]] + +FLAGS + -c, --config= + The name of the app configuration. + [env: SHOPIFY_FLAG_APP_CONFIG] + + --blocking=