diff --git a/README.md b/README.md index 31b8a28..4d2f869 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ **Know before you submit.** Pre-submission compliance scanner for the Apple App Store and Google Play. -Greenlight scans your app — source code, privacy manifests, Android manifests and Gradle builds, IPA binaries, and App Store Connect metadata — against Apple's Review Guidelines and Google Play's Developer Program Policies, catching rejection risks before the stores do. Fully offline, no account, runs in under a second. +Greenlight reads your app (source code, privacy manifests, Android manifests and Gradle builds, IPA binaries, App Store Connect metadata) and checks it against Apple's Review Guidelines and Google Play's Developer Program Policies. Every finding cites the rule it comes from. No account, no uploads, no network. A full preflight on a mid-size project finishes in single-digit milliseconds. -> **Optional runtime tier:** want to confirm flow-dependent guidelines (account deletion, restore purchases, Sign in with Apple) actually *work*, not just exist in source? `greenlight verify` validates them on a cloud device via [Revyl](https://revyl.com). It's entirely separate and opt-in — the static scanner above never needs it. See [`greenlight verify`](#greenlight-verify-path--runtime-flow-validation-via-revyl). +One optional tier is different: `greenlight verify` runs your account-deletion, restore-purchases, and Sign in with Apple flows on a cloud device through [Revyl](https://revyl.com), to confirm they work rather than just exist in source. It needs a Revyl account and it is opt-in. Everything else on this page runs offline. See [`greenlight verify`](#greenlight-verify-path). ## Install @@ -21,238 +21,230 @@ cd greenlight && make build # Binary at: build/greenlight ``` -## Quick Start +## Quick start ```bash -# Run EVERYTHING on your project — one command, zero uploads +# Everything, one command, zero uploads greenlight preflight /path/to/your/project -# Include IPA for binary analysis +# Include an IPA for binary analysis greenlight preflight . --ipa build.ipa + +# Gate CI on it +greenlight preflight . --exit-code ``` -That's it. You get a full report in under a second. +## Severity + +Four levels. The top two fail a CI gate; the bottom two are advisory. + +| Level | Meaning | +|-------|---------| +| CRITICAL | Rejection or install failure is near-certain. Fix before you submit. | +| HIGH | A published deadline, a required declaration, or a check that fails at runtime. | +| WARN | Likely to draw reviewer attention or an information request. | +| INFO | Best practice. | + +`--exit-code` trips on CRITICAL and HIGH, and on a scanner that crashed, so an incomplete scan never reports as a pass. ## Commands -### `greenlight preflight [path]` — The one command to run +### `greenlight preflight [path]` -Runs all scanners in parallel. No account needed. Entirely offline. +Runs every applicable scanner in parallel. Android and iOS projects in one repo are both picked up, so a cross-platform app is checked against both stores in a single pass. ```bash greenlight preflight . # scan current directory greenlight preflight ./my-app --ipa build.ipa # with binary inspection -greenlight preflight . --format json # JSON output for CI/CD -greenlight preflight . --output report.json # write to file +greenlight preflight . --format json # JSON for CI +greenlight preflight . --format sarif --output greenlight.sarif +greenlight preflight . --exit-code # non-zero on CRITICAL/HIGH ``` -**Scanners included:** - | Scanner | Checks | |---------|--------| -| **metadata** | app.json / Info.plist: name, version, bundle ID format, icon, privacy policy URL, purpose strings | -| **codescan** | 30+ code patterns: private APIs, secrets, payment violations, missing ATT, social login, placeholders | -| **privacy** | PrivacyInfo.xcprivacy completeness, Required Reason APIs, tracking SDKs vs ATT implementation | -| **playscan** | Google Play: target API level deadline, restricted permissions, foreground service types, Play Billing version, manifest requirements (Android projects only) | -| **ipa** | Binary: Info.plist keys, launch storyboard, app icons, app size, framework privacy manifests | +| metadata | app.json / Info.plist: name, version, bundle ID format, icon, privacy policy URL, purpose strings | +| codescan | 24 rules over Swift, Objective-C, React Native, and Expo source | +| privacy | PrivacyInfo.xcprivacy completeness, Required Reason APIs, tracking SDKs vs ATT | +| playscan | Google Play policy, target API deadline, restricted permissions, foreground service types, Play Billing version (Android projects only) | +| ipa | Binary: Info.plist keys, launch storyboard, icons, app size, framework privacy manifests | + +Adding `--verify` extends the same command into the runtime tier, so one invocation covers static and runtime: + +```bash +greenlight preflight . --verify --build-name "My App" \ + --var email=qa@acme.com --var password=secret --exit-code +``` -### `greenlight codescan [path]` — Code pattern scan +`--verify` accepts the same targeting flags as the standalone command: `--artifact`, `--build-name`, `--device-model`, `--os-version`, `--var`. + +### `greenlight codescan [path]` ```bash greenlight codescan /path/to/project +greenlight codescan . --config path/to/.greenlight.yml ``` -Scans Swift, Objective-C, React Native, and Expo projects for: -- Private API usage (§2.5.1) — **CRITICAL** -- Hardcoded secrets/API keys (§1.6) — **CRITICAL** -- External payment for digital goods (§3.1.1) — **CRITICAL** -- Dynamic code execution (§2.5.2) — **CRITICAL** -- Cryptocurrency mining (§3.1.5) — **CRITICAL** -- UIWebView (removed API, hard rejection) (§2.5.1) — **CRITICAL** -- Missing Sign in with Apple when using social login (§4.8) -- Missing Restore Purchases for IAP (§3.1.1) -- Missing ATT for ad/tracking SDKs (§5.1.2) -- Account creation without deletion option (§5.1.1) -- Placeholder content in strings (§2.1) +24 rules, roughly 60 patterns, over Swift, Objective-C, React Native, and Expo. + +CRITICAL: + +- Private API usage (§2.5.1) +- Hardcoded secrets and API keys (§1.6) +- External payment for digital goods (§3.1.1) +- Dynamic code execution (§2.5.2) +- Cryptocurrency mining (§3.1.5) +- UIWebView, a removed API and a hard rejection (§2.5.1) + +HIGH: + +- Missing Sign in with Apple alongside social login (§4.8) +- Missing Restore Purchases with IAP (§3.1.1) +- Missing ATT with ad or tracking SDKs (§5.1.2) +- Account creation with no deletion path (§5.1.1) +- A crypto exchange or on-ramp SDK, which usually needs licensing or a legal opinion (§3.1.5(b)) + +WARN: + +- Crypto wallet, which requires an Organization account (§3.1.5(b)), plus exchange signals in copy and references to exchange brands +- Insecure HTTP URLs (§1.6) +- Vague Info.plist purpose strings, and missing required privacy keys (§5.1.1) +- Placeholder content left in strings (§2.1) - References to competing platforms (§2.3) - Hardcoded IPv4 addresses (§2.5) -- Insecure HTTP URLs (§1.6) -- Vague Info.plist purpose strings (§5.1.1) -- Missing encryption export-compliance declaration -- Expo config issues (§2.1) +- WebView-only app pattern (§4.2) +- Expo config problems (§2.1) -### `greenlight playscan [path]` — Google Play policy scan +INFO: debug logging left in production code (§2.1), and no encryption export-compliance declaration. + +Rules that describe a project-level fact, such as "no account deletion anywhere", report once for the whole project rather than once per file that triggers them. + +### `greenlight playscan [path]` ```bash greenlight playscan /path/to/project greenlight playscan --apk app-release.apk # built artifact: merged manifest greenlight playscan --aab app-release.aab # app bundle greenlight playscan . --format json -greenlight playscan . --exit-code # CI gating +greenlight playscan . --exit-code ``` -Checks an Android app against Google Play's Developer Program Policies and its -published distribution deadlines. Android projects are also picked up -automatically by `greenlight preflight`, including the `android/` directory of -an Expo or React Native app, so a cross-platform repo is checked against both -stores in one pass. - -**Deadlines** -- **Target API level** — new apps and updates must target API 36 from - August 31, 2026; apps below API 35 already lose distribution to new users on - newer devices — **CRITICAL / HIGH** -- **Play Billing Library** — v7 and below lose support August 31, 2026, and - there is no direct v7 → v9 upgrade path. Versions reached through a variable - or a version catalog `version.ref` are resolved — **HIGH** - -**Restricted permissions** (each needs an approved use case or declaration form) -- SMS and Call Log — including the July 2026 change that drops phone-call - account verification as a permitted `READ_CALL_LOG` use +Checks an Android app against Google Play's Developer Program Policies and its published distribution deadlines. Every finding links the policy page it comes from. + +Deadlines: + +- Target API level. New apps and updates must target API 36 from August 31, 2026. Apps below API 35 already lose distribution to new users on newer devices. CRITICAL / HIGH +- Play Billing Library. v7 and below lose support on August 31, 2026, and there is no direct v7 to v9 upgrade path. Versions reached through a variable or a version catalog `version.ref` are resolved. HIGH + +Restricted permissions, each of which needs an approved use case or a declaration form: + +- SMS and Call Log, including the July 2026 change that drops phone-call account verification as a permitted `READ_CALL_LOG` use - `MANAGE_EXTERNAL_STORAGE` (All files access) - `QUERY_ALL_PACKAGES`, `REQUEST_INSTALL_PACKAGES` -- `ACCESS_BACKGROUND_LOCATION` (declaration + demo video) -- Broad photo/video access over the system Photo Picker (API 33+) -- Accessibility Service, VPN service, device admin — declared as a component's - `android:permission` rather than `` +- `ACCESS_BACKGROUND_LOCATION`, which needs a declaration and a demo video +- Broad photo and video access over the system Photo Picker (API 33+) +- Accessibility Service, VPN service, and device admin, which are declared as a component's `android:permission` rather than a `` - Overlays, usage stats - Contacts, ahead of the 2026 Contact Permissions policy -**Manifest and build** -- Foreground services missing the base `FOREGROUND_SERVICE` permission, or a - declared type missing its `FOREGROUND_SERVICE_*` permission — both throw at - `startForeground()` — **CRITICAL** -- `specialUse` foreground services needing a Console justification -- `android:exported` missing on components with an intent filter (API 31+) — - the package fails to install — **CRITICAL** -- `android:debuggable="true"` — **CRITICAL** -- `android:usesCleartextTraffic="true"` -- Ads SDK shipped without `com.google.android.gms.permission.AD_ID`, which - silently returns a zeroed advertising ID -- Account creation without the required in-app **and** web deletion paths +Manifest and build: -Every finding cites the policy page it comes from. - -**Scanning a built artifact** (`--apk` / `--aab`) +- Foreground services missing the base `FOREGROUND_SERVICE` permission, or a declared type missing its `FOREGROUND_SERVICE_*` permission. Both throw at `startForeground()`. CRITICAL +- `specialUse` foreground services, which need a Console justification +- `android:exported` missing on components with an intent filter (API 31+), which makes the package fail to install. CRITICAL +- `android:debuggable="true"`. CRITICAL +- `android:usesCleartextTraffic="true"` +- An ads SDK shipped without `com.google.android.gms.permission.AD_ID`, which silently returns a zeroed advertising ID +- Account creation without the required in-app *and* web deletion paths -Passing a build reads the *merged* manifest, so it sees permissions contributed -by library manifests that a source scan structurally cannot. Every policy check -above runs against it, plus the native code checks: +`--apk` and `--aab` read the *merged* manifest, so they see permissions contributed by library manifests that a source scan structurally cannot. Every check above runs against a built artifact, plus native code: -- **16 KB page size** — Google Play requires apps targeting Android 15+ to - support 16 KB memory pages. Checks ELF `LOAD` segment alignment on - `arm64-v8a` libraries, 16 KB zip alignment of uncompressed libraries, and - `GNU_RELRO` presence — **CRITICAL / HIGH** +- 16 KB page size. Google Play requires apps targeting Android 15+ to support 16 KB memory pages. Greenlight checks ELF `LOAD` segment alignment on `arm64-v8a` libraries, 16 KB zip alignment of uncompressed libraries, and `GNU_RELRO` presence. CRITICAL / HIGH -Both formats are read directly: an APK's compiled binary XML and an AAB's -protobuf manifest are decoded in pure Go, so no Android SDK, `aapt2`, or -`bundletool` is needed. +Both formats are decoded in pure Go, an APK's compiled binary XML and an AAB's protobuf manifest alike, so no Android SDK, `aapt2`, or `bundletool` is required. -**Scope.** Scanning *source* reads the `AndroidManifest.xml` and Gradle files in -your repo, which is the *pre-merge* manifest. Permissions contributed by library -manifests only appear once the build merges them, so a clean source scan is not -proof of a clean merged manifest — scan the built artifact to close that gap. -`targetSdk` is resolved from the app module, convention plugins -(`build-logic/`, `buildSrc/`, `build-plugin/`), version catalogs, -`gradle.properties`, and named constants; when it cannot be resolved the scan -says so rather than reporting a pass. +On scope: a source scan reads the `AndroidManifest.xml` and Gradle files in your repo, which is the pre-merge manifest. Permissions contributed by library manifests only appear once the build merges them, so a clean source scan is not proof of a clean merged manifest. Scan the built artifact to close that gap. `targetSdk` is resolved from the app module, convention plugins (`build-logic/`, `buildSrc/`, `build-plugin/`), version catalogs, `gradle.properties`, and named constants; when it cannot be resolved, the scan says so instead of reporting a pass. -### `greenlight privacy [path]` — Privacy manifest validator +### `greenlight privacy [path]` ```bash greenlight privacy /path/to/project ``` -Deep privacy compliance scan: -- PrivacyInfo.xcprivacy exists and is properly configured -- Required Reason APIs detected in code vs declared in manifest -- Tracking SDKs detected vs ATT implementation -- Cross-references everything automatically +Checks that PrivacyInfo.xcprivacy exists and is filled in, finds Required Reason APIs used in code and compares them against what the manifest declares, and cross-references detected tracking SDKs against your ATT implementation. -### `greenlight ipa ` — Binary inspector +### `greenlight ipa ` ```bash greenlight ipa /path/to/build.ipa ``` -Inspects a built IPA for: +Plists are parsed for real, binary and XML both, rather than string-matched. Inspects: + - PrivacyInfo.xcprivacy presence - Info.plist completeness and purpose string quality - App Transport Security configuration -- App icon presence and sizes +- App icon presence and sizes, including icons that live in Assets.car - Launch storyboard presence -- App size vs 200MB cellular download limit +- App size against the 200 MB cellular download limit - Embedded framework privacy manifests -### `greenlight scan --app-id ` — App Store Connect checks +### `greenlight scan --app-id ` ```bash greenlight auth setup # one-time: configure API key greenlight auth login # or: sign in with Apple ID -greenlight scan --app-id 6758967212 # run all tiers +greenlight scan --app-id 6758967212 # run all tiers ``` -API-based checks against your app in App Store Connect: -- Metadata completeness (descriptions, keywords, URLs) -- Screenshot verification for required device sizes -- Build processing status -- Age rating and encryption compliance -- Content analysis (platform references, placeholders) +API-based checks against your app in App Store Connect: metadata completeness, screenshots for required device sizes, build processing status, age rating and encryption compliance, and content analysis for platform references and placeholders. -### `greenlight verify [path]` — Runtime flow validation (via Revyl) +### `greenlight verify [path]` -Static checks confirm a flow **exists** in your source. `verify` confirms it **works** -on a cloud device by handing flow-dependent guidelines to the [Revyl](https://revyl.com) -CLI and running the actual flow. +Static checks confirm a flow *exists* in your source. `verify` confirms it *works*, by handing flow-dependent guidelines to the [Revyl](https://revyl.com) CLI and running them on a cloud device. -This catches what static analysis structurally cannot. A "Delete Account" button wired -to nothing **passes** codescan — the string `deleteAccount` is present, so §5.1.1 is -suppressed and you get GREENLIT — but it dead-ends at runtime, and Apple rejects it under -§5.1.1(v). `verify` runs the flow on a device and catches it. +This is the gap static analysis cannot close. A "Delete Account" button wired to nothing passes codescan: the string `deleteAccount` is in the source, §5.1.1 is suppressed, and you get GREENLIT. At runtime it dead-ends, and Apple rejects under §5.1.1(v). `verify` taps the button. ```bash -greenlight verify . --dry-run # show which flows are claimed + the generated tests, no device +greenlight verify . --dry-run # show claimed flows + generated tests, no device greenlight verify . --build-name "My App" \ - --var email=qa@acme.com --var password=secret # run on a device + --var email=qa@acme.com --var password=secret greenlight verify . --build-name "My App" --flows account-deletion --os-version "iOS 26.2" +greenlight verify . --artifact build/MyApp.app --build-name "My App" # upload, then run +greenlight verify . --platform android --artifact app-release.apk --build-name "My App" ``` -Flows verified (only the ones your app actually claims are run): +Only flows your app actually claims are run: | Flow | Guideline | What runtime proves that static can't | |------|-----------|----------------------------------------| -| `account-deletion` | §5.1.1 | The account is *actually deleted* — not that a `deleteAccount` string exists | -| `restore-purchases` | §3.1.1 | "Restore Purchases" does something — not a silent no-op button | -| `sign-in-apple` | §4.8 | The Apple sign-in sheet actually appears — not a dead control | +| `account-deletion` | §5.1.1 | The account is gone, not that a `deleteAccount` string exists | +| `restore-purchases` | §3.1.1 | "Restore Purchases" does something, rather than being a silent no-op | +| `sign-in-apple` | §4.8 | The Apple sign-in sheet appears, and the control is not dead | -A failed flow becomes a `BLOCK` static analysis could never produce, with a shareable -Revyl report link as evidence. +A failed flow becomes a BLOCK that static analysis could never produce, with a shareable Revyl report link as evidence. `--open` follows the live session in your browser while it runs, and `--exit-code` gates CI on it. -> **Note:** Unlike every other greenlight command, `verify` is **not** offline. It needs -> the [`revyl` CLI](https://docs.revyl.com), a Revyl account (`revyl auth login`), and a -> registered build. It's a deliberately separate, opt-in tier — run `preflight` first to -> get GREENLIT, then `verify` before you submit. +Unlike every other command here, `verify` is not offline. It needs the [`revyl` CLI](https://docs.revyl.com), a Revyl account (`revyl auth login`), and either a registered build or a local artifact to upload with `--artifact`. Revyl runs cloud simulators and emulators, so iOS takes a simulator `.app` and Android takes an `.apk`. A device `.ipa` is rejected with an explanation. -### `greenlight guidelines` — Browse Apple's guidelines +### `greenlight guidelines` ```bash greenlight guidelines list # all sections -greenlight guidelines show 2.1 # specific guideline +greenlight guidelines show 2.1 # a specific guideline greenlight guidelines search "privacy" # full-text search ``` -### Output formats +## Output formats -All scan commands support: +| Command | Formats | +|---------|---------| +| `preflight`, `codescan` | terminal, json, sarif | +| `playscan`, `ipa`, `verify` | terminal, json | +| `scan` | terminal, json, junit | -```bash ---format terminal # colored terminal output (default) ---format json # JSON for CI/CD pipelines ---format sarif # SARIF 2.1.0 for GitHub code scanning (preflight, codescan) ---output file.json # write to file instead of stdout -``` +`--output file` writes to a file instead of stdout. `--exit-code` is available on `preflight`, `playscan`, and `verify`. -Upload `--format sarif` to GitHub code scanning to get findings inline in the -Security tab and on PRs: +Upload SARIF to GitHub code scanning and findings show up in the Security tab and inline on pull requests: ```yaml - run: greenlight preflight . --format sarif --output greenlight.sarif @@ -261,63 +253,75 @@ Security tab and on PRs: sarif_file: greenlight.sarif ``` +## CI + +```yaml +# GitHub Actions +- name: App Store + Play compliance + run: greenlight preflight . --exit-code +``` + +That fails the job on any CRITICAL or HIGH finding, and on a scanner that crashed mid-scan. To keep the report as an artifact too: + +```yaml +- run: greenlight preflight . --format json --output greenlight-report.json --exit-code +``` + ## Configuration (`.greenlight.yml`) -Drop a `.greenlight.yml` in your project root to tune the code scan — disable a -rule, change a rule's severity, or ignore paths: +Drop a `.greenlight.yml` in your project root to tune the code scan: ```yaml rules: hardcoded-ipv4: - severity: info # downgrade (info | warn | critical) + severity: info # info | warn | critical platform-reference: enabled: false # turn a rule off ignore: - - vendor # skip a directory (anywhere in the tree) + - vendor # skip a directory, anywhere in the tree - "*.generated.ts" # skip by filename - src/legacy # skip a path ``` -It applies to the code scan (`codescan`, and the codescan part of `preflight`). -Point at a specific file with `codescan --config path/to/.greenlight.yml`. +It applies to `codescan` and to the codescan portion of `preflight`. Point at a specific file with `codescan --config path/to/.greenlight.yml`. -## Claude Code Skill +To silence one line rather than a whole rule, use an inline directive on the offending line or the line directly above it: -Greenlight works as a Claude Code skill for AI-assisted compliance fixing. Claude runs the scan, reads the output, fixes every issue in your code, and re-runs until GREENLIT. +```swift +let host = "10.1.2.3" // greenlight:ignore hardcoded-ipv4 +``` -### Setup +A bare `// greenlight:ignore` suppresses every rule on that line. Naming the rule is better: it keeps the other checks live. -Add the SKILL.md to your project's `.claude/` directory or install as a plugin: +## Claude Code skill -```bash -# Copy skill file into your project -mkdir -p .claude/skills -cp /path/to/greenlight/SKILL.md .claude/skills/greenlight.md +Greenlight ships as a Claude Code plugin, so Claude can run the scan, read the findings, fix them in your code, and re-run until GREENLIT. -# Or reference it in your CLAUDE.md -echo "See greenlight skill: /path/to/greenlight/SKILL.md" >> CLAUDE.md +```bash +# In Claude Code +/plugin marketplace add RevylAI/greenlight +/plugin install greenlight ``` -Then tell Claude: *"Run greenlight preflight and fix everything until it passes"* +Or copy the skill file into a project by hand: -Claude will: -1. Run `greenlight preflight .` -2. Read every finding -3. Fix each issue (CRITICAL first, then WARN, then INFO) -4. Re-run and repeat until GREENLIT +```bash +mkdir -p .claude/skills +cp /path/to/greenlight/SKILL.md .claude/skills/greenlight.md +``` -## Codex Skill +Then: *"Run greenlight preflight and fix everything until it passes."* Claude works down the severity ladder, CRITICAL first, then HIGH, WARN, and INFO, re-running after each pass. -Greenlight includes a Codex-native skill package at `codex-skill/`. +## Codex skill -### Setup +A Codex-native skill package lives at `codex-skill/`. ```bash mkdir -p ~/.codex/skills/app-store-preflight-compliance cp -R codex-skill/* ~/.codex/skills/app-store-preflight-compliance/ ``` -Then in Codex, invoke: +Then, in Codex: ```text Use $app-store-preflight-compliance to run Greenlight preflight and fix all findings until GREENLIT. @@ -327,60 +331,44 @@ Use $app-store-preflight-compliance to run Greenlight preflight and fix all find ``` greenlight -├── preflight Run ALL checks — one command -│ ├── metadata app.json / Info.plist local analysis -│ ├── codescan 30+ rejection-risk code patterns +├── preflight Run every applicable scanner, one command +│ ├── metadata app.json / Info.plist +│ ├── codescan 24 rejection-risk rules │ ├── privacy Privacy manifest + Required Reason APIs -│ └── ipa Binary inspection (optional) +│ ├── playscan Google Play policy (Android projects) +│ ├── ipa Binary inspection (with --ipa) +│ └── --verify Chain the runtime tier onto the same run │ -├── codescan Code-only scanning -├── privacy Privacy-only scanning -├── ipa Binary-only inspection +├── codescan Code only, tunable via .greenlight.yml +├── privacy Privacy manifest only +├── playscan Google Play only, source or --apk / --aab +├── ipa Binary only │ -├── verify Runtime flow validation on a cloud device (via Revyl) -│ ├── account-deletion §5.1.1 — the account is actually deleted -│ ├── restore-purchases §3.1.1 — Restore Purchases isn't a no-op -│ └── sign-in-apple §4.8 — the Apple sign-in sheet actually appears +├── verify Runtime flow validation on a cloud device (Revyl) +│ ├── account-deletion §5.1.1 the account is actually deleted +│ ├── restore-purchases §3.1.1 Restore Purchases isn't a no-op +│ └── sign-in-apple §4.8 the Apple sign-in sheet appears │ ├── scan App Store Connect API checks (tiers 1-4) -│ ├── Tier 1 Metadata & completeness +│ ├── Tier 1 Metadata and completeness │ ├── Tier 2 Content analysis │ ├── Tier 3 Binary inspection │ └── Tier 4 Historical pattern matching │ ├── auth App Store Connect authentication -│ ├── login Apple ID + 2FA session auth +│ ├── login Apple ID + 2FA session │ ├── setup API key configuration -│ ├── status Show current auth state +│ ├── status Current auth state │ └── logout Remove credentials │ └── guidelines Built-in Apple Review Guidelines database ├── list All 5 sections with subsections - ├── show Specific guideline details + ├── show A specific guideline └── search Full-text search ``` -## CI/CD Integration - -```yaml -# GitHub Actions -- name: App Store compliance check - run: | - greenlight preflight . --format json --output greenlight-report.json - # Fail the pipeline if critical issues found - if jq -e '.summary.critical > 0' greenlight-report.json > /dev/null; then - echo "CRITICAL issues found — fix before submission" - exit 1 - fi -``` - -```yaml -# JUnit output for test reporting (scan command only) -greenlight scan --app-id $APP_ID --format junit --output greenlight.xml -``` - ## Built by Revyl Greenlight catches App Store rejections. [Revyl](https://revyl.com) catches bugs. -The mobile reliability platform. AI-powered testing for mobile apps — write tests in natural language, run them on cloud devices. +The mobile reliability platform. Write tests in natural language, run them on cloud devices.