Skip to main content

CI/CD Integration

Skylos fits into CI in three different ways. The right choice depends on whether you want local-only exit codes, cloud-managed policy, or GitHub-native hard enforcement.

Here, local-only means the analysis runs on the CI worker without a Skylos Cloud upload. It does not promise an offline run: dependency checks can query OSV or package registries, and direct image scans contact a registry through Trivy.

Choose a CI Mode​

GoalUse thisNotes
Local-only CI gateskylos . --danger --secrets --quality --ai-defects --gateExplicit analyzers; no cloud state required
Kubernetes or GPU source/build proofskylos . --select RULES --gateExact source/config correlation with an independent Reliability threshold
Built GPU artifact gateskylos preflight build/appExact artifact report: exit 0 PASS, 1 FAIL, 2 UNKNOWN
Workflow security reviewskylos . --dangerScans .github/workflows/* and local action metadata
Cloud upload with dashboard policyskylos . --uploadUses project policy, suppressions, and cloud history
Cloud gate in one line on other CI systemsskylos cloud --gateEvery check, upload, and exit 1 when the Skylos Cloud gate fails; set SKYLOS_TOKEN
GitHub required checksskylos cicd init plus branch protectionPR quality gate and Done run without Cloud credentials; the GitHub App provides a separate Cloud-managed PR gate

GitHub Actions Workflow Security​

skylos . --danger also scans GitHub Actions workflows and local action metadata. It flags CI/CD supply-chain risks such as privileged triggers, broad GITHUB_TOKEN permissions, unpinned actions, unsafe checkout credentials, template injection, secret overexposure, mutable containers, OIDC release risk, and missing timeouts on privileged jobs.

The same --danger invocation also runs deployment/runtime contract analysis. Kubernetes and GPU results whose category is Reliability stay in the separate reliability JSON bucket and gate threshold; they do not inflate Security counts. JSON output, uploads, GitHub annotations, and PR review formatting preserve this category.

See GitHub Actions Security for setup guidance and the full scanner scope.

--danger also checks .gitlab-ci.yml for GitLab CI misconfigurations (SKY-D314 to SKY-D323 in the rules reference), plus Dependabot config, Dockerfiles, Docker Compose files and systemd units.

It does not parse Jenkins, CircleCI, Bitbucket Pipelines, Azure Pipelines or Buildkite configuration for misconfiguration rules. Those CIs still run the Skylos pull request gate; see Other CI Providers.

GitHub Actions with OIDC​

Run PR scans and tests without Cloud credentials. Upload full scans only on pushes to the default branch, using GitHub OIDC. Generate this workflow with:

python -m pip install --upgrade "skylos>=4.46.0"
skylos cicd init

The onboarding generator, Done discovery and options below require Skylos 4.46.0 or newer. Skylos 4.45.0 does not include this generated workflow or the --no-upload, --done and --default-branch options.

See the first gated PR guide for setup and branch protection. Use skylos cicd init --no-upload if you do not use Cloud.

Preconditions:

  • the Skylos project is bound to the GitHub repository
  • the Skylos GitHub App is installed on that repository
  • only the default-branch upload job has id-token: write

The example below assumes a Python project with pytest and one Cloud project for the repository. Replace main with your default branch and edit the Done dependency step for your project. Use the App's per-root workflow for multiple monorepo projects. skylos cicd init detects your branch and whether to add Done automatically.

name: Skylos Analysis

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
skylos:
if: github.event_name == 'pull_request'
name: Skylos Quality Gate
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- run: python -I -m pip install "skylos>=4.46.0"
- name: Scan changed code
run: |
pr_base_ref="origin/$GITHUB_BASE_REF"
skylos . --danger --secrets --quality --ai-defects --sca --no-upload --diff-base "$pr_base_ref" --diff "$pr_base_ref" --json -o skylos-results.json
- name: Quality gate
if: always()
run: skylos cicd gate --input skylos-results.json --summary

done:
if: github.event_name == 'pull_request'
name: Skylos Done
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- run: python -I -m pip install "skylos>=4.46.0"
- name: Install project test dependencies
run: python -I -m pip install -e . pytest
- name: Run tests and check the change is finished
run: skylos done --base "origin/$GITHUB_BASE_REF"

cloud-upload:
if: github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
name: Skylos Cloud upload
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- run: python -I -m pip install "skylos>=4.46.0"
- run: skylos sync pull
- run: skylos . --danger --secrets --quality --ai-defects --sca --upload
env:
SKYLOS_COMMIT: ${{ github.sha }}
SKYLOS_BRANCH: ${{ github.ref_name }}

The generated workflow also adds annotations and PR review comments. The example above shows the scan, test and upload jobs without those optional reporting steps. When dependency checks (--sca) are selected, a workflow generated by a Skylos version that has --review-upgrades also passes it to the pull request scan, so each upgraded npm or PyPI package is compared with its previous release (see Upgrade Review). Done reads its settings from the base branch, runs your tests, and writes a receipt to the job summary. A skipped or unfinished blocking check cannot pass.

The GitHub App's Cloud-managed PR workflow is a separate path. It scans PR code in an unprivileged job, then publishes through an isolated trusted job. Adding OIDC permission or a stored token to an ordinary PR test job does not turn it into that workflow.

In the App-generated Done job, Python test dependencies share the scanner's Python environment. Keep them compatible with the selected Skylos version; the job stops before Done runs if installation replaces that version. If your Python build backend creates local artifacts such as *.egg-info/, add narrow patterns to the reviewed base .gitignore before requiring the check. The clean-checkout guard still rejects source changes; do not ignore all untracked files to make a receipt pass.

The App workflow uses pull_request_target. GitHub's default event policy applies to public repositories without an existing applicable event policy. It currently evaluates this trigger; enforcement starts November 2, 2026 for affected repositories using that default policy before general availability. Check that your applicable policy permits the App workflow before requiring its check.

How OIDC works:

  1. GitHub Actions issues a short-lived OIDC token
  2. Skylos verifies it
  3. Cloud verifies the repository and App binding, then resolves the project, using the project subpath when supplied
  4. the upload proceeds with no SKYLOS_TOKEN

OIDC failure modes​

OIDC upload fails when:

  • no project matches the verified repository and requested project subpath
  • several projects match because the request omits a subpath or duplicates exist for that repository and subpath
  • the GitHub App is not installed on the repository
  • the upload job is missing id-token: write
  • an ordinary PR job tries to upload instead of a default-branch push job

GitHub Actions with SKYLOS_TOKEN​

Use this for explicit secret management. Keep the stored token in a trusted default-branch upload job; PR scans and tests do not need it. A local API key upload is stored as unverified and cannot pass the Cloud GitHub gate. Put SKYLOS_TOKEN in a GitHub environment named skylos-security and restrict that environment to your default branch.

name: Skylos Cloud upload

on:
push:
branches: [main]

permissions:
contents: read

jobs:
cloud-upload:
if: github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
runs-on: ubuntu-latest
timeout-minutes: 15
environment: skylos-security
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- run: python -I -m pip install skylos
- name: Run Skylos
env:
SKYLOS_TOKEN: ${{ secrets.SKYLOS_TOKEN }}
run: skylos . --danger --secrets --quality --ai-defects --upload

Replace main with your default branch.

Use SKYLOS_TOKEN for:

  • CI providers without OIDC
  • explicit project selection in a trusted CI job
  • local policy sync or upload

For GitHub OIDC, skylos sync pull uses the same accepted CI identity as the upload. It does not require a stored token in the default-branch upload job.

Advisory Quality Checks​

When adopting standards-backed quality checks in an existing repository, run them as advisory first. The workflow should warn, annotate, and write a summary, but return exit code 0 until legacy findings are under control.

Recommended advisory bundle:

  • Ruff for Python lint policy
  • mypy or pyright for Python type-check policy
  • TypeScript compile/build scripts for packages with tsconfig.json
  • Rustfmt and Clippy for Rust crates
  • diff-aware Skylos scans using --diff-base and --diff
- name: Skylos advisory scan
run: skylos . --danger --secrets --quality --ai-defects --no-upload --diff-base origin/main --diff origin/main --json -o skylos-results.json

- name: Advisory quality summary
if: always()
run: skylos cicd gate --input skylos-results.json --summary --advisory

Use a hard gate later, after findings are diff-aware, baseline-aware, or low enough to enforce.

Pull Request Review Comments​

Skylos can post inline GitHub pull request review comments for findings on changed lines. Use this when you want reviewers to see Skylos findings directly on the PR diff instead of only in the Actions log or job summary.

The generated workflow from skylos cicd init includes this review step. If you use the Skylos GitHub Action directly, set its mode input to review. If you write your own workflow, grant pull-requests: write, expose GH_TOKEN, and run skylos cicd review after creating a JSON report.

name: Skylos PR Review

on:
pull_request:

permissions:
contents: read

jobs:
skylos:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- run: python -I -m pip install skylos

- name: Run Skylos on changed code
run: |
pr_base_ref="origin/${GITHUB_BASE_REF:-main}"
skylos . --danger --quality --secrets --ai-defects --no-upload --diff-base "$pr_base_ref" --diff "$pr_base_ref" --json -o skylos-results.json

- name: Post GitHub annotations
if: always()
run: skylos cicd annotate --input skylos-results.json

- name: Post PR review comments
if: always() && github.event.pull_request.head.repo.full_name == github.repository
env:
GH_TOKEN: ${{ github.token }}
run: |
pr_base_ref="origin/${GITHUB_BASE_REF:-main}"
skylos cicd review --input skylos-results.json --diff-base "$pr_base_ref" --max-comments 25

skylos cicd review auto-detects the PR number and repository in GitHub Actions. Outside CI, pass them explicitly:

skylos cicd review --input skylos-results.json --pr 42 --repo owner/repo

Use --summary-only when you want a single PR summary comment without inline comments. Use --max-comments to cap review noise on large diffs. Fork PRs still get the scan and annotations; the comment step is skipped because their GitHub token has read-only permissions.

Pulling Policy in CI​

The generated default-branch upload job pulls policy with its GitHub OIDC identity before scanning:

- name: Pull Skylos policy
run: skylos sync pull

In a trusted job that uses an API key instead, provide SKYLOS_TOKEN:

- name: Pull Skylos policy
env:
SKYLOS_TOKEN: ${{ secrets.SKYLOS_TOKEN }}
run: skylos sync pull

That writes .skylos/config.yaml and .skylos/suppressions.json in the checkout. Keep policy sync and its credentials out of ordinary PR test jobs.

Generated Workflow Helpers​

skylos cicd init​

Use skylos cicd init from Skylos 4.46.0 or newer to scaffold the workflow described here. On GitLab CI, Jenkins, Bitbucket Pipelines, Azure Pipelines and CircleCI it sets up that CI's gate instead (Skylos 5.1.0 or newer); see Other CI Providers.

Examples:

skylos cicd init
skylos cicd init --no-upload
skylos cicd init --done
skylos cicd init --defend

The generated workflow has:

  • Skylos Quality Gate on PRs: a changed-line scan, gate summary, annotations and review comments
  • Skylos Done on PRs when pytest tests or a configured test command are found: tests and a completion receipt
  • Skylos Cloud upload on default-branch pushes: policy sync and a full scan using GitHub OIDC

Upload is on by default; --no-upload omits it. --done and --no-done override test discovery. --default-branch overrides branch detection, and --scan-path changes the scanned directory. The generated workflow pins the installed Skylos version, so regenerate it after upgrading Skylos.

For multiple Cloud projects in a monorepo, use the GitHub App's generated per-root workflow. CLI --scan-path does not route the generated skylos sync pull step: it sends no GitHub project-subpath header and can fail when several projects match the repository.

skylos sync setup​

skylos sync setup asks for an API key to connect the local repository and scaffold optional hooks and workflow files.

Current behavior:

  • it asks for a token
  • it can scaffold pre-push hooks, pre-commit config, and a GitHub Actions workflow
  • its generated CI workflow scans PRs locally and uploads default-branch pushes with GitHub OIDC
  • use skylos cicd init for the PR gate and discovered Done job described above

GitHub App Enforcement​

The GitHub App is the GitHub-native enforcement layer.

Recommended order:

  1. get uploads working first
  2. save the exact GitHub repo URL on the project
  3. install the GitHub App: in the project's Settings, step 1 of Merge blocking on GitHub is Connect GitHub
  4. open or update a pull request so the Skylos Quality Gate check runs on it
  5. require the check: in the project's Settings, step 4 of Merge blocking on GitHub has Download ruleset

Require the check with a ruleset​

The ruleset Skylos gives you requires Skylos Quality Gate from the Skylos App on your default branch. A workflow job with the same name can't pass it.

  1. In the project's Settings, select Download ruleset.
  2. On GitHub, open the repository's Settings -> Rules -> Rulesets, select New ruleset -> Import a ruleset, choose the file, then select Create.
  3. Back in Skylos, select Check again. The step shows Done.

If you connected a GitHub organization, the repository also shows Enforcing under Repository coverage on the Posture page.

Skylos offers the file only after the check has run on a pull request, so the rule never waits for a check that can't arrive. Direct pushes to the default branch need a passing check too. To let admins skip it, add them to the ruleset's bypass list on GitHub.

"Merge anyway" in Skylos (Workspace and Enterprise plans) updates the same check, so it still works with the ruleset.

If the repository uses a merge queue, Skylos doesn't offer the ruleset yet: Skylos doesn't check merge-queue commits, so the queue would wait forever.

Skylos only reads branch protection and rulesets; it never changes them. The auto-configure toggle in the project settings (Workspace and Enterprise plans, off by default) only opens the workflow pull request after you connect GitHub.

Other CI Providers​

Skylos runs on any CI. skylos cicd init finds the CI your repository uses and sets up the pull request gate for it. CIs other than GitHub Actions need Skylos 5.1.0 or newer; check with skylos --version.

Repository hasskylos cicd init sets up
.github/workflows/GitHub Actions: writes .github/workflows/skylos.yml
.gitlab-ci.ymlGitLab CI
JenkinsfileJenkins
bitbucket-pipelines.ymlBitbucket Pipelines
azure-pipelines.ymlAzure Pipelines
.circleci/config.ymlCircleCI
.buildkite/, .travis.yml, .drone.yml, .woodpecker.yml, .teamcity/prints the commands to add
no CI filethe CI of origin's host (github.com, gitlab.com, bitbucket.org, dev.azure.com), else GitHub Actions

If the CI file does not exist yet, Skylos writes it. If it exists, Skylos does not edit it: it prints the block to add and where it goes. Pick a CI with --ci github|gitlab|jenkins|bitbucket|azure|circleci|other.

A repository with .github/workflows/ gets the GitHub workflow, as before. Skylos also names any other CI file it found and the --ci command for it. Without .github/workflows/, two or more of the GitLab, Jenkins, Bitbucket, Azure and CircleCI files and no --ci make Skylos write nothing and ask you to pick.

Every generated config runs the same gate on the lines the pull request changes, and fails the build when the gate fails:

skylos . --danger --quality --ai-defects --secrets --sca --review-upgrades --baseline --gate --diff

--review-upgrades downloads the old and new release of each npm or PyPI package the pull request upgrades and fails the gate when the new one adds install-time or start-up code (see Upgrade Review). It is added whenever --sca is selected. Configs written by Skylos versions without this flag leave it out.

The review fails closed: when it cannot check an upgrade, the gate stops with exit 2 instead of passing. That happens when a registry cannot be reached, when more than 100 package versions change (adding a lockfile or switching package manager usually does), when a changed lockfile is over 64 MB or cannot be read, and when a private package is neither in internal_packages nor downloaded from a host in private_registries. List private packages and registries under [tool.skylos.supply_chain] on the default branch. See Upgrade Review.

--baseline hides findings saved in .skylos/baseline.json. Commit one with skylos baseline . if you want that. Without the file, Skylos prints "No baseline found" and checks every changed line. For agent-config and publish-job rules, malware, SKY-SCA-UPG001, SKY-SCA-HRD001 and SKY-SCA-AGE001, a baseline entry counts only when the base branch's .skylos/baseline.json has it too, so a pull request cannot excuse its own findings by editing the baseline (see Baselines).

The config installs the Skylos version you ran skylos cicd init with, for example skylos[dart]==5.1.1. Change that pin when you upgrade.

Then:

  1. Commit the file, or the block Skylos printed, on a branch and open a pull request.
  2. Check that the Skylos gate runs on it.
  3. Make that check required before merging, in your code host's branch protection.

skylos doctor shows which CI files run Skylos. Run in CI, it also shows which branch --diff compares with.

To upload to Skylos Cloud from a CI other than GitHub Actions, use skylos cloud --gate. It runs every check, uploads the findings, and exits 1 when the Skylos Cloud gate (your project's policy in Skylos Cloud) fails. That is not the local skylos . --gate, which uses [tool.skylos.gate] and uploads nothing. Set SKYLOS_TOKEN to a project token as a secret in a trusted job, and select Mark for CI on that token in the project's Settings. Without the mark, its uploads are unverified: they show in Skylos Cloud but don't publish a check or mark issues fixed.

skylos cloud --gate

GitLab CI​

The skylos job runs in merge request pipelines with GIT_DEPTH: "0", fetches the target branch and runs the gate. If your .gitlab-ci.yml declares stages:, it needs a test stage. For the merge request Code Quality widget, see GitLab Code Quality.

Jenkins​

The Skylos stage runs only in pull request builds (when { changeRequest() }) of a Multibranch Pipeline job. It installs Skylos in a virtualenv under $WORKSPACE_TMP, outside the checkout, so the install is not part of the diff. The agent needs python3 3.10 or newer.

The stage fetches the target branch only when the clone does not have it. If that fetch fails on a private repository, the shell step has no Git credentials. Use the "merge with the target branch" pull request strategy, which fetches it during checkout, or give the step credentials.

Jenkins does not own the pull request; your code host does. Make the Jenkins status check required there.

Bitbucket Pipelines​

The step runs in pull request pipelines with clone: depth: full and fetches the destination branch before the scan.

Azure Pipelines​

The pipeline checks out with fetchDepth: 0, which brings in the target branch. It does not run its own git fetch, because Azure does not keep checkout credentials for later steps. For Azure Repos, add the pipeline as the target branch's Build validation policy.

CircleCI​

The job skips builds without an open pull request. CircleCI does not expose the pull request's target branch, so the job compares with your default branch: the --default-branch you pass, else origin's HEAD, else main. Change the branch in the file if pull requests go elsewhere.

Other CIs​

skylos cicd init --ci other prints the three commands to add to a pull request build step. The step needs Python 3.10 or newer. With Skylos 5.1.1 and main as the default branch, they are:

python -I -m pip install skylos==5.1.1
git fetch --no-tags origin "+refs/heads/main:refs/remotes/origin/main"
skylos . --danger --quality --ai-defects --secrets --sca --baseline --gate --diff origin/main

Skylos versions that have --review-upgrades print it after --sca in the last command.

Dart files​

The Jenkins and "other CI" commands install plain skylos. Dart support, skylos[dart], is built from source and needs a C compiler, which many Jenkins agents do not have. To scan Dart files, install skylos[dart] on an agent that has one.

Without it, Skylos skips the Dart files and reports coverage as incomplete. The gate still decides on the other files. It stops with exit 2 only when most of the files in scope could not be analyzed, or when you add --strict or set require_complete = true under [tool.skylos.gate.coverage].

The GitLab, Bitbucket, CircleCI and Azure configs run on images with a compiler and install skylos[dart].

Which branch --diff compares with​

With no value, --diff compares with the pull request's target branch:

CITarget branch fromPull request build when
GitHub ActionsGITHUB_BASE_REFGITHUB_BASE_REF is set
GitLab CICI_MERGE_REQUEST_TARGET_BRANCH_NAMEGITLAB_CI=true and the variable is set
JenkinsCHANGE_TARGETCHANGE_ID is set (Multibranch Pipeline) in a Jenkins build: JENKINS_URL, JENKINS_HOME or a jenkins- BUILD_TAG
Bitbucket PipelinesBITBUCKET_PR_DESTINATION_BRANCHthe variable is set
Azure PipelinesSYSTEM_PULLREQUEST_TARGETBRANCHSYSTEM_PULLREQUEST_PULLREQUESTID is set
BuildkiteBUILDKITE_PULL_REQUEST_BASE_BRANCHBUILDKITE_PULL_REQUEST is a number
Travis CITRAVIS_BRANCHTRAVIS_PULL_REQUEST is a number
DroneDRONE_TARGET_BRANCHDRONE_BUILD_EVENT=pull_request
WoodpeckerCI_COMMIT_TARGET_BRANCHCI=woodpecker and CI_PIPELINE_EVENT=pull_request

Each variable counts only inside its own CI and only on a pull request build. Anywhere else, --diff compares with origin/main. On CircleCI, TeamCity and other CIs, pass the branch: --diff origin/develop.

The target branch has to be in the clone. Many CIs clone only the pull request branch, or only recent history. When it is missing, Skylos stops with exit 2 and prints the command to run first, for example:

On Jenkins, run this before the scan: git fetch --no-tags origin +refs/heads/develop:refs/remotes/origin/develop

In a shallow clone that command includes --unshallow.

Uploading to Skylos Cloud from other CIs​

skylos cicd init adds Cloud uploads only for GitHub Actions, through GitHub OIDC. On other CIs, add a separate full scan with --upload and a SKYLOS_TOKEN secret.

Diff-scoped reports cannot be uploaded. A scan with --upload and --diff or --diff-base stops with "diff-scoped results cannot be uploaded as a full scan". Keep the gate step and the upload step separate.

Use a project token made for CI, not the one skylos login saved on a laptop. Until an owner or admin selects Mark for CI on that token (project Settings, Project tokens), its uploads are unverified. Unverified scans are stored and shown, but they don't post a pull request check or status, mark issues fixed, or become the baseline. Tokens saved by skylos login can't be marked.

For Bitbucket and Azure pull request checks, see Bitbucket and Azure Pipelines. For GitLab, see GitLab managed uploads. Skylos Cloud posts merge request comments on GitLab only on the Workspace and Enterprise plans.

GitLab CI:

skylos:
image: python:3.11
script:
- pip install skylos
- skylos . --danger --quality --ai-defects --upload
variables:
SKYLOS_TOKEN: $SKYLOS_TOKEN

CircleCI:

- run:
name: Skylos Scan
command: skylos . --danger --quality --ai-defects --upload
environment:
SKYLOS_TOKEN: $SKYLOS_TOKEN

Jenkins:

stage('Skylos Scan') {
environment {
SKYLOS_TOKEN = credentials('skylos-token')
}
steps {
sh 'pip install skylos'
sh 'skylos . --danger --quality --ai-defects --upload'
}
}

Local Gate vs Cloud Gate in CI​

Local gate​

skylos . --danger --secrets --quality --ai-defects --gate

Use this when you only want CLI exit codes from local config. A bare --gate does not enable every analyzer.

For a narrow source/config release proof:

# Kubernetes exposure path
skylos . --select SKY-DEP001,SKY-DEP002,SKY-DEP003 --gate

# CUDA image, build-architecture, and TensorRT packaging intent
skylos . --select SKY-GPU001,SKY-GPU002,SKY-GPU003 --gate

GPU leaf selection automatically retains SKY-GPU000 so a missing or invalid target contract fails closed. Reliability uses max_reliability = 0 by default. See Release Reliability for contract setup.

After producing the local GPU artifact, gate that exact output separately:

skylos preflight build/app

Preflight uses its own result contract: 0 is PASS, 1 is a proved FAIL, and 2 is UNKNOWN or invalid input. Treat 2 as a blocked release in CI. See Built Artifact Preflight.

Cloud gate​

skylos . --upload

Use this when you want the cloud project to evaluate:

  • dashboard policy
  • suppressions
  • baseline history
  • strict mode
  • AI assurance
  • PR-diff-aware new issue detection when available

Troubleshooting​

OIDC upload says the repo is not linked​

Set the exact GitHub repo URL on the Skylos project.

OIDC upload says the repo binding is ambiguous​

Make sure the request identifies the intended project subpath and only one project matches that repository and subpath. Use the App's per-root workflow for multiple monorepo projects; CLI --scan-path alone does not route policy sync.

skylos sync pull fails in CI​

sync pull accepts GitHub OIDC in an authorized default-branch upload job. Check id-token: write, the project repo URL and the App installation. For local use or a provider without OIDC, use a saved API key or SKYLOS_TOKEN. Do not move policy sync into an ordinary PR test job.

The workflow generated by sync setup still wants a token​

sync setup asks for a token to connect your local repository. Its generated default-branch upload uses GitHub OIDC. An older workflow that references SKYLOS_TOKEN can be replaced with skylos cicd init; review the generated file before committing it.

Upload works but there is no GitHub-native PR status​

Basic upload is not the same thing as GitHub App enforcement. Save the repo URL, install the GitHub App, and configure branch protection.