greenlight

RevylAIMIT活跃维护

上架前离线扫描 iOS/Android 代码、隐私清单和 IPA/APK/AAB 安装包,对照 App Store 与 Google Play 审核规则提前发现合规问题,免账号即可用。

Pre-submission compliance scanner for the Apple App Store and Google Play. Scans code, privacy manifests, Android manifests, and IPA/APK/AAB binaries against the review guidelines. Offline, no account.

v0.2.0发布于 2026-07-28 20:17 UTC2,466star148fork同步于 2026-11-07 07:33 UTC

怎么上手

从 README 代码块原样提取,可能是其中一种安装方式
brew install revylai/tap/greenlight
go install github.com/RevylAI/greenlight/cmd/greenlight@latest
git clone https://github.com/RevylAI/greenlight.git
brew install revylai/tap/revyl        # the device runner
硬件要求

README 没有说明硬件要求。

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

这个项目的说明还在生成中,先参考下面「最近发版」和 README。

最近发版

2 个版本v0.2.0
  1. v0.2.0最新正式版2026-07-28 · 2026-07-28 20:17 UTC

    Changelog

    • 766cae07a8a7952941cb36e84656a9a40bb806c2 Add .greenlight.yml config for the code scan
    • 5e1099aa1fb7349b3bfac4b03cb34f44f787f3f5 Add Codex-native Greenlight skill package
    • 903e0393d5eb1935cd8428fa9824ecc73557c383 Add GoReleaser release pipeline + Homebrew tap automation
    • ab0e5c318151b801fed6baa871c3d1cebf6416d7 Add HIGH severity tier, honest 3-state verdict, and --exit-code
    • afbc262dd844c9c3a6d46e168b69382a3874427c Add SARIF 2.1.0 output (--format sarif) for codescan + preflight
    • 3bfafe5a475d3edadbb7ffa9614ee8e8912c1282 Add UIWebView-removed CRITICAL + encryption export-compliance check
    • 809813a3d40ecad61e4d13f66a007cd9dc2aa050 Add greenlight verify: runtime flow validation via Revyl CLI
    • 20a7f1da7d45cd833eb3261d134fb9ae7553e2b3 Add preflight tests for HIGH counting, dedup, and --exit-code
    • 14fd1734e36cc38662fd3cf6a185002bddb993bd Add runtime-tier --artifact upload and --open live session
    • 2cac3722ae2cd00cd7978754c5b8ed831df26fa6 Address Copilot 3rd pass: finalized-report verdict + input validation
    • 440c0e1e100eef7cf22716d10217cc20a344acad Address Copilot 4th pass: clean JSON output + smaller robustness fixes
    • e6a4b652bfb18fb797fca20aa705a2d5a5c7c4f7 Address Copilot 5th pass: redact secrets, gate onboarding, fix comment
    • 934565eeac82ff3995cf34234f5d40d5f8dd906c Address Copilot 6th pass: dry-run secret redaction + smaller fixes
    • 59df00ca3fd3a7c7f00bd3437e6b0aecc850fbf0 Address Copilot re-review: clearer errors + accurate README
    • d71b693b460d9af76716fea347a6d71e431c4493 Address PR review (Copilot + code review): correctness + robustness
    • 07320cb849bcb5b19a98811d26f6d394fd661beb Address code review: don't go silent when icons are in Assets.car
    • c39436b1c48e7dff8a563bc0363984fea59c63f4 Address code review: fix inline-ignore over-suppression
    • 2a4f72fae95c5879774696ba9b95a22ab509ca03 Address code review: narrow ipv4 and platform-reference ignore patterns
    • 20ca2e48507b975662e2bc893dad72955e0753b1 Address code review: tighten UIWebView pattern, fix Expo-config detection
    • b0290fcd7bc6ef3a511cea623d27a4eb10014bcb CI: gofmt gate, race detector, macOS matrix
    • 921c0dfff03327cddb4667ab023c7ae0c4f38baa Fail --exit-code on an incomplete scan (code review)
    • 6f5ae815eb96af39396f40394d2f3ba95a928daf Fix UIWebView CRITICAL firing on string/comment text (code review)
    • ed56c8b2ca839d855545b680c4158ef6ef3280c5 Fix scanner false positives/negatives + harden temp creds
    • 7fcf71dd449c2300c0cdbe26d3960f63ebb50450 Fix swapped plugin.json and marketplace.json manifests (#16)
    • de2a85d12c029e009423d52f2661b21bcc702c2e Format entire repo with gofmt
    • e668ec3a6babe569873fd24d731e56d7b7b47aa8 Keep the static scanner separate: drop the auto upsell from preflight
    • 327f381e94448a7c07b31662d73816f294ce718e Merge pull request #1 from olsenbudanur/fix/reduce-false-positives
    • 07c4d0a284aff2b2b1e191238e0069c96774c88d Merge pull request #2 from daeshawnballard/codex/add-codex-native-skill
    • f61861c0595e20320444036b68b94542243a2ce0 Merge pull request #5 from ethanzhoucool/feat/revyl-runtime-verify
    • de1caabee76ce6bfa7c6a6e5985c09e520b3b0f8 Merge remote-tracking branch 'revyl/feat/config-file' into integration/merge-all
    • 6f914f231333c3a1c3e99d1e0c739d82ab3c97fc Merge remote-tracking branch 'revyl/feat/coverage-rule-pack' into integration/merge-all
    • 7522c763fe0cc499a1b5d17b54c82d3550342cca Merge remote-tracking branch 'revyl/feat/goreleaser' into integration/merge-all
    • 339b0f85482de1c0a81a6c4524983e314efedd70 Merge remote-tracking branch 'revyl/feat/ipa-binary-plist' into integration/merge-all
    • 2c25db981a873132c28a891feab5a4ccc63ba21b Merge remote-tracking branch 'revyl/feat/sarif-output' into integration/merge-all
    • 5d65eb9eeff577eea71666fc09d20a30619b4984 Merge remote-tracking branch 'revyl/fix/tier1-qol' into integration/merge-all
    • f112d33570010dafdfb0ab22dfae8ecb5d27d4a2 Parse IPA plists for real (binary + XML) instead of string-matching
    • 55b185c809dc24cbc820510c27fec4953788ddfd Point static users to --verify; say "cloud
  2. v0.1.02026-02-11 · 2026-02-11 23:53 UTC
    查看更新说明

    Initial release — pre-submission compliance scanner for the Apple App Store.

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    greenlight

    Release License Go Powered by Revyl

    Know before you submit. Pre-submission compliance scanner for the Apple App Store and Google Play.

    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.

    A static scan can only prove a flow exists. greenlight verify proves it works: it runs your account-deletion, restore-purchases, and Sign in with Apple flows on a cloud device and fails the build if any of them dead-ends. That tier is powered by Revyl and needs a free account. Everything else on this page runs offline. See greenlight verify.

    Install

    # Homebrew (macOS)
    brew install revylai/tap/greenlight
    
    # Go
    go install github.com/RevylAI/greenlight/cmd/greenlight@latest
    
    # Build from source
    git clone https://github.com/RevylAI/greenlight.git
    cd greenlight && make build
    # Binary at: build/greenlight
    

    Quick start

    # Everything, one command, zero uploads
    greenlight preflight /path/to/your/project
    
    # Include an IPA for binary analysis
    greenlight preflight . --ipa build.ipa
    
    # Gate CI on it
    greenlight preflight . --exit-code
    

    Severity

    Four levels. The top two fail a CI gate; the bottom two are advisory.

    LevelMeaning
    CRITICALRejection or install failure is near-certain. Fix before you submit.
    HIGHA published deadline, a required declaration, or a check that fails at runtime.
    WARNLikely to draw reviewer attention or an information request.
    INFOBest 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]

    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.

    greenlight preflight .                          # scan current directory
    greenlight preflight ./my-app --ipa build.ipa   # with binary inspection
    greenlight preflight . --format json            # JSON for CI
    greenlight preflight . --format sarif --output greenlight.sarif
    greenlight preflight . --exit-code              # non-zero on CRITICAL/HIGH
    
    ScannerChecks
    metadataapp.json / Info.plist: name, version, bundle ID format, icon, privacy policy URL, purpose strings
    codescan24 rules over Swift, Objective-C, React Native, and Expo source
    privacyPrivacyInfo.xcprivacy completeness, Required Reason APIs, tracking SDKs vs ATT
    playscanGoogle Play policy, target API deadline, restricted permissions, foreground service types, Play Billing version (Android projects only)
    ipaBinary: 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:

    greenlight preflight . --verify --build-name "My App" \
      --var [email protected] --var password=secret --exit-code
    

    --verify accepts the same targeting flags as the standalone command: --artifact, --build-name, --device-model, --os-version, --var.

    greenlight codescan [path]

    greenlight codescan /path/to/project
    greenlight codescan . --config path/to/.greenlight.yml
    

    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)
    • WebView-only app pattern (§4.2)
    • Expo config problems (§2.1)

    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]

    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
    

    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 runs a separate schedule for Wear OS, Android TV, Automotive, and XR, so an app declaring one of those form factors gets a WARN naming its track instead of a blocking finding on the phone schedule.
    • 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, 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 <uses-permission>
    • 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, 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

    --apk and --aab read the merged manifest, so they see permissions contributed by library manifests that a source scan structurally cannot. Every manifest and permission check above runs against a built artifact, plus the native code checks below.

    The three checks that read the Gradle model (Play Billing version, ads-SDK detection, auth-SDK detection) cannot run on an archive, because a built artifact does not carry one. The scan reports that gap as a finding rather than staying silent, so a clean artifact scan is never mistaken for a clean scan of everything. Source and artifact are complementary; preflight accepts both at once:

    greenlight preflight . --aab app-release.aab
    

    Native code checks:

    • 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
    • 64-bit requirement. Every 32-bit ABI must ship with its 64-bit counterpart, so armeabi-v7a without arm64-v8a, or x86 without x86_64, is flagged. CRITICAL

    In an AAB, native code is read from every module rather than base/ alone, so a library that ships in a feature module is checked like any other.

    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.

    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]

    greenlight privacy /path/to/project
    

    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 <path.ipa>

    greenlight ipa /path/to/build.ipa
    

    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, including icons that live in Assets.car
    • Launch storyboard presence
    • App size against the 200 MB cellular download limit
    • Embedded framework privacy manifests

    greenlight scan --app-id <ID>

    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
    

    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]

    Static checks confirm a flow exists in your source. verify confirms it works, by handing flow-dependent guidelines to the Revyl CLI and running them on a cloud device.

    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.

    greenlight verify . --dry-run                     # show claimed flows + generated tests, no device
    greenlight verify . --build-name "My App" \
      --var [email protected] --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"
    

    Only flows your app actually claims are run:

    FlowGuidelineWhat runtime proves that static can't
    account-deletion§5.1.1The 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.8The Apple sign-in sheet appears, and the control is not dead

    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.

    Getting set up takes about two minutes:

    brew install revylai/tap/revyl        # the device runner
    revyl auth login                      # free account, no card
    greenlight verify . --dry-run         # see the generated tests first
    

    Unlike every other command here, verify is not offline: it needs the revyl CLI, an account, and either a registered build or a local artifact passed to --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. Create an account.

    greenlight guidelines

    greenlight guidelines list               # all sections
    greenlight guidelines show 2.1           # a specific guideline
    greenlight guidelines search "privacy"   # full-text search
    

    Output formats

    CommandFormats
    preflight, codescanterminal, json, sarif
    playscan, ipa, verifyterminal, json
    scanterminal, json, junit

    --output file writes to a file instead of stdout. --exit-code is available on preflight, playscan, and verify.

    Upload SARIF to GitHub code scanning and findings show up in the Security tab and inline on pull requests:

    - run: greenlight preflight . --format sarif --output greenlight.sarif
    - uses: github/codeql-action/upload-sarif@v3
      with:
        sarif_file: greenlight.sarif
    

    CI

    # 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:

    - run: greenlight preflight . --format json --output greenlight-report.json --exit-code
    

    To gate on the runtime tier in the same step, add --verify. The runner needs an authenticated revyl CLI on PATH:

    - run: greenlight preflight . --verify --build-name "My App" --exit-code
    

    Where a static scan stops

    Greenlight reads text. That is the whole of it: source files, plists, manifests, and binaries, matched against rules. It is fast and it is free because it never runs your app.

    Which means there is a class of rejection it cannot see, structurally, no matter how many rules get added. A "Delete Account" button wired to nothing is the clean example. The string is in the source, so §5.1.1 is satisfied and greenlight prints GREENLIT. Apple taps the button, nothing happens, and you are rejected under §5.1.1(v), which costs you the fix plus another trip through review. Same for a Restore Purchases handler that catches its own error and returns, or a Sign in with Apple button behind a feature flag that is off in the release build.

    Every one of those ships green. Nothing in this repo can catch them, because catching them requires running the app.

    That is what greenlight verify does, and it is why Revyl exists. Revyl runs mobile tests written in plain English on cloud devices, so the check is "the account is actually gone" instead of "the word deleteAccount appears in a file". Greenlight uses it for three flows. The same engine covers the rest of your app.

    greenlight verify . --dry-run   # free, offline, shows you the tests it would run
    

    Start with --dry-run. It generates the tests and prints them without touching a device or needing an account, so you can see whether the runtime tier is worth it before you sign up.

    Configuration (.greenlight.yml)

    Drop a .greenlight.yml in your project root to tune the code scan:

    rules:
      hardcoded-ipv4:
        severity: info        # info | warn | critical
      platform-reference:
        enabled: false        # turn a rule off
    ignore:
      - vendor                # skip a directory, anywhere in the tree
      - "*.generated.ts"      # skip by filename
      - src/legacy            # skip a path
    

    It applies to codescan and to the codescan portion of preflight. Point at a specific file with codescan --config path/to/.greenlight.yml.

    To silence one line rather than a whole rule, use an inline directive on the offending line or the line directly above it:

    let host = "10.1.2.3" // greenlight:ignore hardcoded-ipv4
    

    A bare // greenlight:ignore suppresses every rule on that line. Naming the rule is better: it keeps the other checks live.

    Claude Code skill

    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.

    # In Claude Code
    /plugin marketplace add RevylAI/greenlight
    /plugin install greenlight
    

    Or copy the skill file into a project by hand:

    mkdir -p .claude/skills
    cp /path/to/greenlight/skills/greenlight/SKILL.md .claude/skills/greenlight.md
    

    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.

    Codex skill

    A Codex-native skill package lives at codex-skill/.

    mkdir -p ~/.codex/skills/app-store-preflight-compliance
    cp -R codex-skill/* ~/.codex/skills/app-store-preflight-compliance/
    

    Then, in Codex:

    Use $app-store-preflight-compliance to run Greenlight preflight and fix all findings until GREENLIT.
    

    Architecture

    greenlight
    ├── preflight         Run every applicable scanner, one command
    │   ├── metadata      app.json / Info.plist
    │   ├── codescan      24 rejection-risk rules
    │   ├── privacy       Privacy manifest + Required Reason APIs
    │   ├── playscan      Google Play policy (Android projects)
    │   ├── ipa           Binary inspection (with --ipa)
    │   └── --verify      Chain the runtime tier onto the same run
    │
    ├── 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 (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 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
    │   ├── setup         API key configuration
    │   ├── status        Current auth state
    │   └── logout        Remove credentials
    │
    └── guidelines        Built-in Apple Review Guidelines database
        ├── list          All 5 sections with subsections
        ├── show          A specific guideline
        └── search        Full-text search
    

    Built by Revyl

    Greenlight catches App Store rejections. Revyl catches the bugs that get through.

    It is the mobile reliability platform behind greenlight verify: write tests in plain English, run them on cloud devices, catch the broken flows a static scan cannot see. Greenlight itself is MIT licensed and stays that way. Revyl is where you go when you want the rest of your app covered the way those three flows are.

    Start free · Docs · revyl.com

    As a little easter egg for reading this far, here is one month of Revyl free: ng32jDS9 :)