# SubmitGate

Cross-platform mobile compliance & risk scanner. Deterministic, CI-first — scans iOS and Android app artifacts for privacy, security, and compliance issues.

# Support

report issues at [submitgate-support](https://github.com/toybox-software/submitgate-support/issues)

## Supported Artifacts

- **iOS**: `.xcarchive`, `.ipa`, `.app`
- **Android**: `.apk`, `.aab`

## Quickstart

```bash
# Scan an iOS app
npx submitgate scan ios MyApp.xcarchive --summary

# Scan an Android app
npx submitgate scan android MyApp.apk --summary
```

## License Token

A license token is required. Get a free trial at the SubmitGate portal (`https://submit-gate.com/portal/`) — enter your email and check your inbox.

Set the token as an environment variable:

```bash
export SUBMITGATE_LICENSE="<your-token>"
```

> Dev builds may also require `SUBMITGATE_LICENSE_PUBLIC_KEY_PEM` — see the packaged docs for details.

## GitHub Actions CI

Pin the version for deterministic CI. Replace `<VERSION>` with the version you want (e.g. `0.36.0`).

### Prerequisites

1. Add `SUBMITGATE_LICENSE` as a [GitHub Actions secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions) in your repo or org.
2. Your workflow must build or download the app artifact before scanning. Replace `<ARTIFACT_PATH>` with the path to your built artifact.

### SARIF scan (recommended)

Uploads results to GitHub Code Scanning so findings appear as alerts on PRs.

```yaml
name: submitgate

on:
  pull_request:
  push:
    branches: [main]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write
    steps:
      - uses: actions/checkout@v4

      # TODO: build or download your app artifact here.

      - name: Run SubmitGate
        id: submitgate
        continue-on-error: true
        env:
          SUBMITGATE_LICENSE: ${{ secrets.SUBMITGATE_LICENSE }}
        run: |
          npx -y submitgate@<VERSION> scan <PLATFORM> <ARTIFACT_PATH> \
            --format sarif \
            --ci --ci-provider github \
            > submitgate.sarif

      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: submitgate.sarif

      - name: Fail if issues found
        if: steps.submitgate.outcome != 'success'
        run: exit 1
```

**iOS example** (scanning a prebuilt xcarchive):

```yaml
- name: Run SubmitGate
  id: submitgate
  continue-on-error: true
  env:
    SUBMITGATE_LICENSE: ${{ secrets.SUBMITGATE_LICENSE }}
  run: |
    npx -y submitgate@<VERSION> scan ios build/MyApp.xcarchive \
      --format sarif --ci --ci-provider github > submitgate.sarif
```

**Android example** (scanning an APK):

```yaml
- name: Run SubmitGate
  id: submitgate
  continue-on-error: true
  env:
    SUBMITGATE_LICENSE: ${{ secrets.SUBMITGATE_LICENSE }}
  run: |
    npx -y submitgate@<VERSION> scan android app/build/outputs/apk/release/app-release.apk \
      --format sarif --ci --ci-provider github > submitgate.sarif
```

### JSON + Markdown scan (no SARIF upload)

```yaml
- name: Run SubmitGate
  env:
    SUBMITGATE_LICENSE: ${{ secrets.SUBMITGATE_LICENSE }}
  run: |
    npx -y submitgate@<VERSION> scan <PLATFORM> <ARTIFACT_PATH> \
      --format both \
      --fail-on BLOCKER
```

### Notes

- `--format sarif` writes SARIF to stdout — redirect to a file.
- `--format both` writes `report.json` and `report.md` to the working directory.
- Exit codes: `0` = clean, `1` = findings at threshold, `6` = license error.
- Scans are fully offline — no network calls during the scan.
- `security-events: write` permission is required for SARIF upload.

## Configuration

Scaffold config files in your project:

```bash
npx submitgate init --ci github --baseline
```

This creates `submitgate.config.json`, `submitgate.policy.json`, and a GitHub Actions workflow.

### Policy files

Policy files let you override severities, disable rules, or set per-rule fail thresholds:

```json
{
  "schemaVersion": 1,
  "rules": [
    {
      "ruleId": "IOS_PRIVACY_MANIFEST",
      "when": { "baselineState": "new" },
      "severity": "BLOCKER"
    },
    {
      "ruleId": "IOS_PRIVACY_MANIFEST",
      "when": { "baselineState": "unchanged" },
      "severity": "INFO"
    }
  ]
}
```

Pass with `--policy ./submitgate.policy.json`.

### Baselines

Baselines let CI fail only on **new** findings, not pre-existing ones:

```bash
# One-time: create baseline from current state
npx submitgate baseline create <PLATFORM> <ARTIFACT_PATH> --out baseline.json

# CI: scan against baseline (fails only on regressions)
npx submitgate scan <PLATFORM> <ARTIFACT_PATH> --baseline baseline.json --fail-on BLOCKER
```

Commit `baseline.json` to your repo. Do not regenerate it on every CI run.

## Features

- **iOS**: Privacy manifest validation, debuggable build detection, App Tracking Transparency checks
- **Android**: Network security config, debuggable builds, target SDK validation, ad ID usage, permission declarations
- **Output formats**: JSON, Markdown, SARIF
- **Policy engine**: Customizable severity rules with baseline differential analysis
- **CI integration**: GitHub Actions annotations, step summaries, SARIF upload

## Further Reading

Full CI integration docs (policy files, baselines, aggregate scans, debug flags) are included in the npm package at [`github-actions.md`](https://github.com/toybox-software/submitgate-support/blob/main/github-actions.md).

## License

See [LICENSE](./LICENSE) for details.
