Static scanner and Codex skill for Apple App Store review risk preflight checks.
Project description
App Store Review Risk
Catch likely App Store rejection risks in an Xcode repository or pull request before Apple sees the build—locally, target-aware, and with file-level evidence an AI coding agent can verify and help fix.
app-store-review-risk combines a deterministic static scanner with an agent review workflow. It checks Apple-platform source, project settings, metadata, privacy declarations, entitlements, StoreKit flows, account handling, and submission artifacts without pretending that a heuristic can guarantee approval.
Private by design: the default static scanner has no network integration and does not upload source code or findings. Optional --xcodebuild mode invokes the repository's local Xcode tooling and is subject to that project's package-resolution behavior. When used in GitHub Actions, the scanner runs inside the workflow runner under that repository's normal GitHub Actions controls.
Part of an open-source Apple quality toolkit: make the UI automation-ready, exercise it in iOS Simulator with an AI planner, then preflight the release here.
30-Second Agent Preflight
Install the skill with the open Agent Skills CLI:
npx skills add https://github.com/Kofiloski/app-store-review-risk --skill app-store-review-risk
Or install it with GitHub CLI:
gh skill install Kofiloski/app-store-review-risk app-store-review-risk --agent codex --scope user
Then ask your coding agent:
Review this iOS app before App Store submission. Check the submitted target and
current Git diff for privacy, permissions, StoreKit, account, metadata, and
other likely rejection risks. Use $app-store-review-risk and cite file evidence.
The public bundle lives at skills/app-store-review-risk/, matching its frontmatter name and the Agent Skills discovery convention. The bundle contains only agent instructions, UI metadata, and focused references; the CLI and GitHub Action remain versioned at the repository root. A root SKILL.md compatibility entry point remains for older direct-clone installs, while new installs should use the nested package.
30-Second CLI Preflight
uvx app-store-review-risk . --submitted-target MyApp
For a persistent command, run pipx install app-store-review-risk. The scanner is packaged for Python 3.10 and newer, and PyPI is the low-friction CLI channel; GitHub remains the canonical source for the Agent Skill, Action, release history, and development.
Why GitHub and PyPI Are Separate
One version tag serves three related deliverables, but they are distributed through two channels:
- The GitHub release versions the Agent Skill in
skills/app-store-review-risk/, the root composite action, and the source repository. Installing the skill withgh skill installornpx skills adddoes not involve PyPI. - The PyPI workflow publishes only the optional
app-store-review-riskPython CLI wheel and source distribution. It runs automatically when the GitHub release is published.
If Trusted Publisher setup was missing or PyPI was temporarily unavailable, manually dispatch Publish to PyPI from the main branch and enter the existing release tag. The workflow checks out that exact tag, verifies it matches all package version metadata, rebuilds it, and skips files PyPI already accepted. A manual retry never creates or replaces the GitHub release or Agent Skill.
Pushing an exact vX.Y.Z tag runs the repository-owned release workflow, which validates the tag, creates the GitHub release, and dispatches the PyPI workflow with GitHub's built-in token. Maintainers do not need to authorize GitHub CLI with personal or organization scopes.
For the first PyPI release, register a pending Trusted Publisher at https://pypi.org/manage/account/publishing/ with project app-store-review-risk, owner Kofiloski, repository app-store-review-risk, workflow publish-pypi.yml, and environment pypi. These values must match exactly; no API token is stored in GitHub.
Real Scanner Output
This finding comes from the checked-in examples/demo-app fixture, not a mocked interface:
# Apple App Review Risk Scan Summary
Target: `examples/demo-app`
Platforms: iOS (high), iPadOS (high)
Findings: HIGH=1, MEDIUM=0, LOW=1, INFO=0
- HIGH `permissions-missing-nscamerausagedescription`: Potential protected-resource use without NSCameraUsageDescription (medium)
evidence: `Sources/CameraView.swift:4: _ = AVCaptureDevice.default(for: .video)`
Reproduce the complete output:
scripts/scan_apple_app_review_risks.py examples/demo-app --format compact --max-findings 4
The path is shortened in the README; examples/demo-output.txt contains the normalized complete result used by the test suite.
Why It Is More Than a Checklist
- Deterministic first pass: the CLI produces stable finding IDs and exact evidence before an agent reasons about context.
- Target-aware: scope source, plist, privacy manifest, and generated build-setting checks to the Xcode target being submitted.
- Diff-aware: separate new, changed-file, and resolved risks so existing unrelated findings do not automatically block a pull request.
- Apple-platform aware: cover iOS, iPadOS, macOS, Mac Catalyst, watchOS, tvOS, visionOS, TestFlight, and notarization paths.
- Agent-ready: compact text and JSON formats keep the first pass small while platform references support deeper review only where needed.
Run in GitHub Actions
The repository is a root composite action. This example checks only App Review risks introduced or touched by a pull request:
name: App Store review risk
on:
pull_request:
permissions:
contents: read
jobs:
preflight:
runs-on: macos-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: Kofiloski/app-store-review-risk@v0.3.1
with:
path: .
submitted-target: MyApp
diff: ${{ github.event.pull_request.base.sha }}...${{ github.sha }}
fail-on: high
Static scans also work on Linux runners. Set xcodebuild: true only on a macOS runner, and provide scheme, project, or workspace when the repository needs explicit Xcode selection.
What It Covers
Info.plistpermission descriptions and generated plist build settingsPrivacyInfo.xcprivacy, required-reason APIs, tracking, and privacy collection clues- entitlements, StoreKit, subscriptions, restore paths, and external purchase language
- Guideline 4.8 login-option signals, account deletion, and UGC moderation clues
- private API and placeholder-content signals
- App Store Connect artifact gaps such as screenshots, review notes, privacy answers, support URLs, and demo access
- multiple app targets, tests, extensions, examples, admin tools, and synchronized Xcode groups
Install Options
With pipx:
pipx install app-store-review-risk
With pip:
python3 -m pip install app-store-review-risk
Run once without a persistent install:
uvx app-store-review-risk . --submitted-target MyApp
Install an immutable GitHub release directly:
pipx install "git+https://github.com/Kofiloski/app-store-review-risk.git@v0.3.1"
From a local clone:
python3 -m pip install .
Without installing:
scripts/scan_apple_app_review_risks.py /path/to/apple-app
Scanner Commands
Scan an app repository:
app-store-review-risk /path/to/apple-app
Scope code and configuration findings to the submitted target:
app-store-review-risk /path/to/apple-app --submitted-target MyApp
Use Xcode for more exact target metadata:
app-store-review-risk /path/to/apple-app --xcodebuild --scheme MyScheme
Review risks introduced or touched by a Git diff:
app-store-review-risk /path/to/apple-app --diff origin/main...HEAD
Compare a release with the working tree or another committed ref:
app-store-review-risk /path/to/apple-app --base-ref v1.2.0
app-store-review-risk /path/to/apple-app --base-ref v1.2.0 --head-ref v1.3.0
Fail a CI job on new or changed high-severity findings:
app-store-review-risk /path/to/apple-app --diff origin/main...HEAD --fail-on high
Working-tree comparisons include non-ignored untracked files. In diff mode, --fail-on applies to new findings and existing findings whose evidence touches changed files, rather than every unchanged finding in the repository.
Output Formats
compactis the default and is optimized for release and agent triage.compact-jsonis structured while remaining token-conscious.markdownproduces a human-readable review report.jsonincludes the complete machine-readable scan result.
Treat findings as investigation leads. Inspect the cited source and App Store Connect configuration before treating a heuristic signal as a real rejection risk.
Important Notice
This tool cannot guarantee App Store, TestFlight, or notarization approval. Apple documentation, App Store Connect configuration, and App Review remain the source of truth.
Always verify high-impact conclusions against current official guidance:
- App Review Guidelines
- Human Interface Guidelines
- relevant Apple Developer documentation and App Store Connect help
External purchase and account links remain storefront-specific. Guideline 4.8 describes the privacy outcomes required of an equivalent login option rather than naming a single mandatory identity provider. The scanner deliberately reports these change-prone areas as items to verify, not automatic policy verdicts.
Repository Layout
skills/app-store-review-risk/SKILL.md: published agent workflow, reporting format, and review disciplineskills/app-store-review-risk/agents/andskills/app-store-review-risk/references/: skill UI metadata and focused platform guidancesrc/app_store_review_risk/: installable CLI packageaction.ymlandscripts/run-action.sh: composite GitHub Action entry pointexamples/demo-app/andexamples/demo-output.txt: reproducible scanner demonstrationllms.txt: compact machine-readable repository mapCITATION.cff: software citation metadatascripts/check-skill.sh: full local validation
Limitations
- Static heuristics can produce false positives or miss behavior behind runtime configuration, remote services, feature flags, or App Store Connect-only setup.
- Symbolic links are not followed, so linked source outside the scanned tree needs separate review.
- A repository cannot prove privacy answers, subscription products, entitlement approval, backend availability, or reviewer credentials unless those artifacts are present.
- The source scanner does not inspect compiled
.ipaor.xcarchivebinaries.
Validate
./scripts/check-skill.sh
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file app_store_review_risk-0.3.1.tar.gz.
File metadata
- Download URL: app_store_review_risk-0.3.1.tar.gz
- Upload date:
- Size: 51.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc109b23e420bfac6c4735575354831eceb45997c8961de1a7f9c3e847305c4e
|
|
| MD5 |
4d1cf3fca447f165040fa84aafcc633d
|
|
| BLAKE2b-256 |
263ad513402f00355e9996d49589517c8ce564d0ffc6fef6ceccc06cf5ef735c
|
Provenance
The following attestation bundles were made for app_store_review_risk-0.3.1.tar.gz:
Publisher:
publish-pypi.yml on Kofiloski/app-store-review-risk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
app_store_review_risk-0.3.1.tar.gz -
Subject digest:
dc109b23e420bfac6c4735575354831eceb45997c8961de1a7f9c3e847305c4e - Sigstore transparency entry: 2176140832
- Sigstore integration time:
-
Permalink:
Kofiloski/app-store-review-risk@b2eb8715eb4467d9e7b920edfd191c7c9d89f975 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Kofiloski
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@b2eb8715eb4467d9e7b920edfd191c7c9d89f975 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file app_store_review_risk-0.3.1-py3-none-any.whl.
File metadata
- Download URL: app_store_review_risk-0.3.1-py3-none-any.whl
- Upload date:
- Size: 35.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c983ae0350c285b9c5019ed7b3003b32fd30a5b1c641c6400b8ba5eda7e2095
|
|
| MD5 |
f7b5e4d5af256a5ac1fba56e8eb52646
|
|
| BLAKE2b-256 |
0f8e346819d8ff32d0c065f7c9629e01d706af0fbc01ce70e8f0f5ec931ae05c
|
Provenance
The following attestation bundles were made for app_store_review_risk-0.3.1-py3-none-any.whl:
Publisher:
publish-pypi.yml on Kofiloski/app-store-review-risk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
app_store_review_risk-0.3.1-py3-none-any.whl -
Subject digest:
5c983ae0350c285b9c5019ed7b3003b32fd30a5b1c641c6400b8ba5eda7e2095 - Sigstore transparency entry: 2176140839
- Sigstore integration time:
-
Permalink:
Kofiloski/app-store-review-risk@b2eb8715eb4467d9e7b920edfd191c7c9d89f975 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Kofiloski
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@b2eb8715eb4467d9e7b920edfd191c7c9d89f975 -
Trigger Event:
workflow_dispatch
-
Statement type: