Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 244 additions & 0 deletions .github/workflows/codex-security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

name: Codex Security Release Qualification

on:
push:
tags:
- "v*.*.*-pre.*"
workflow_call:
inputs:
candidate_ref:
description: Pre-release tag to scan (vMAJOR.MINOR.PATCH-pre.N)
required: true
type: string
stable_ref:
description: Optional previous stable tag override
required: false
default: ""
type: string
allow_full_bootstrap:
description: Allow a full scan when no previous stable tag exists
required: false
default: false
type: boolean
outputs:
base_sha:
description: Previous stable commit, empty for a full bootstrap scan
value: ${{ jobs.analyze.outputs.base_sha }}
candidate_sha:
description: Qualified pre-release commit
value: ${{ jobs.analyze.outputs.candidate_sha }}
category:
description: Code Scanning category for the release train
value: ${{ jobs.analyze.outputs.category }}
train:
description: Stable version targeted by the pre-release train
value: ${{ jobs.analyze.outputs.train }}
secrets:
CODEX_SECURITY_API_KEY:
required: true
workflow_dispatch:
inputs:
candidate_ref:
description: Pre-release tag to scan (vMAJOR.MINOR.PATCH-pre.N)
required: true
type: string
stable_ref:
description: Optional previous stable tag override
required: false
type: string
allow_full_bootstrap:
description: Allow a full scan when no previous stable tag exists
required: false
default: false
type: boolean

permissions:
actions: read
contents: read
security-events: write

concurrency:
group: codex-security-release-qualification
cancel-in-progress: true

env:
CODEX_SECURITY_REASONING_EFFORT: medium
NVIDIA_INFERENCE_BASE_URL: https://inference-api.nvidia.com/v1
NVIDIA_INFERENCE_MODEL: openai/openai/gpt-5.6-sol

jobs:
analyze:
name: Codex Security (${{ inputs.candidate_ref || github.ref_name }})
runs-on: ubuntu-latest
timeout-minutes: 120
outputs:
base_sha: ${{ steps.range.outputs.base_sha }}
candidate_sha: ${{ steps.range.outputs.candidate_sha }}
category: ${{ steps.range.outputs.category }}
train: ${{ steps.range.outputs.train }}
steps:
# Install the trusted scanner before repository-controlled files exist in
# the workspace, and invoke it later through its absolute path.
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
with:
node-version: "26"
package-manager-cache: false

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14"

- name: Install Codex Security
run: |
set -euo pipefail
npm install \
--prefix "$RUNNER_TEMP/codex-security" \
--ignore-scripts \
--no-audit \
--no-fund \
@openai/codex-security@0.1.24

- name: Verify Codex Security
env:
CODEX_SECURITY_BIN: ${{ runner.temp }}/codex-security/node_modules/.bin/codex-security
run: |
set -euo pipefail
test -x "$CODEX_SECURITY_BIN"
"$CODEX_SECURITY_BIN" --version

- name: Check out the pre-release
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.candidate_ref || github.ref }}
fetch-depth: 0
persist-credentials: false

- name: Resolve release range
id: range
env:
ALLOW_FULL_BOOTSTRAP: ${{ inputs.allow_full_bootstrap || false }}
CANDIDATE_REF: ${{ inputs.candidate_ref || github.ref_name }}
STABLE_REF: ${{ inputs.stable_ref || '' }}
run: |
set -euo pipefail
git show-ref --verify --quiet refs/remotes/origin/main

args=(
--candidate "$CANDIDATE_REF"
--main-ref origin/main
)
if [ -n "$STABLE_REF" ]; then
args+=(--stable "$STABLE_REF")
fi
if [ "$ALLOW_FULL_BOOTSTRAP" = "true" ]; then
args+=(--allow-full-bootstrap)
fi

node tasks/scripts/codex-security-release-range.mjs "${args[@]}"

- name: Scan changes since the previous stable
env:
BASE_SHA: ${{ steps.range.outputs.base_sha }}
CODEX_SECURITY_BIN: ${{ runner.temp }}/codex-security/node_modules/.bin/codex-security
CODEX_SECURITY_STATE_DIR: ${{ runner.temp }}/codex-security-state
HEAD_SHA: ${{ steps.range.outputs.candidate_sha }}
NVIDIA_INFERENCE_API_KEY: ${{ secrets.CODEX_SECURITY_API_KEY }}
OPENAI_API_KEY: ${{ secrets.CODEX_SECURITY_API_KEY }}
SCAN_DIR: ${{ runner.temp }}/codex-security-results
SCAN_SCOPE: ${{ steps.range.outputs.scan_scope }}
run: |
set -euo pipefail
install -d -m 700 "$CODEX_SECURITY_STATE_DIR" "$SCAN_DIR"

target_args=()
if [ "$SCAN_SCOPE" = "diff" ]; then
target_args=(--diff "$BASE_SHA" --head "$HEAD_SHA")
elif [ "$SCAN_SCOPE" != "full" ]; then
echo "::error::Unsupported Codex Security scan scope: $SCAN_SCOPE"
exit 2
fi

"$CODEX_SECURITY_BIN" scan . \
"${target_args[@]}" \
--auth api-key \
--model "$NVIDIA_INFERENCE_MODEL" \
--effort "$CODEX_SECURITY_REASONING_EFFORT" \
--codex 'model_provider="nvidia"' \
--codex 'model_providers.nvidia.name="NVIDIA Inference"' \
--codex "model_providers.nvidia.base_url=\"$NVIDIA_INFERENCE_BASE_URL\"" \
--codex 'model_providers.nvidia.env_key="NVIDIA_INFERENCE_API_KEY"' \
--codex 'model_providers.nvidia.wire_api="responses"' \
--codex 'model_providers.nvidia.supports_websockets=false' \
--output-dir "$SCAN_DIR" \
--headless > /dev/null

- name: Export SARIF
env:
CODEX_SECURITY_BIN: ${{ runner.temp }}/codex-security/node_modules/.bin/codex-security
SARIF_FILE: ${{ runner.temp }}/codex-security.sarif
SCAN_DIR: ${{ runner.temp }}/codex-security-results
run: |
set -euo pipefail
"$CODEX_SECURITY_BIN" export "$SCAN_DIR" \
--export-format sarif \
--source-root "$GITHUB_WORKSPACE" \
--output "$SARIF_FILE"

- name: Summarize findings
env:
BASE_TAG: ${{ steps.range.outputs.base_tag }}
CANDIDATE_TAG: ${{ steps.range.outputs.candidate_tag }}
COMMIT_COUNT: ${{ steps.range.outputs.commit_count }}
SARIF_FILE: ${{ runner.temp }}/codex-security.sarif
SCAN_SCOPE: ${{ steps.range.outputs.scan_scope }}
TRAIN: ${{ steps.range.outputs.train }}
run: |
set -euo pipefail
finding_count=$(jq '[.runs[]?.results[]?] | length' "$SARIF_FILE")
{
echo "### Codex Security release qualification"
echo
echo "- Train: \`$TRAIN\`"
echo "- Candidate: \`$CANDIDATE_TAG\`"
if [ "$SCAN_SCOPE" = "diff" ]; then
echo "- Previous stable: \`$BASE_TAG\`"
echo "- Commits in cumulative diff: $COMMIT_COUNT"
else
echo "- Scope: approved full bootstrap scan"
fi
echo "- Coverage: complete"
echo "- Findings: $finding_count"
echo
echo "Findings are informational during the observation phase."
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload SARIF to Code Scanning
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
sarif_file: ${{ runner.temp }}/codex-security.sarif
ref: refs/heads/main
sha: ${{ steps.range.outputs.candidate_sha }}
category: ${{ steps.range.outputs.category }}

result:
name: OpenShell / Codex Security (informational)
if: always()
needs: analyze
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Evaluate scanner execution
env:
ANALYZE_RESULT: ${{ needs.analyze.result }}
run: |
set -euo pipefail
if [ "$ANALYZE_RESULT" != "success" ]; then
echo "::error::Codex Security release qualification did not complete successfully."
exit 1
fi
echo "Codex Security completed; findings remain informational."
1 change: 1 addition & 0 deletions .github/workflows/release-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
tags:
- "v*.*.*"
- "!v*.*.*-pre.*"
workflow_dispatch:
inputs:
tag:
Expand Down
33 changes: 25 additions & 8 deletions CI.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ The GitHub ruleset should require the `OpenShell / ...` statuses published by `R

## Informational security reports

Security analysis that does not need NVIDIA infrastructure runs directly on
GitHub-hosted runners. These workflows receive no secrets. The PR-oriented
reports run on fork pull requests without waiting for copy-pr-bot. Scanner jobs
request `security-events: write` to publish SARIF to Code Scanning. GitHub
permits Code Scanning uploads from `pull_request` runs even when fork and
Dependabot contexts receive a read-only `GITHUB_TOKEN`, so those scanners upload
results directly and also retain report artifacts:
Security workflow compute runs directly on GitHub-hosted runners instead of
NVIDIA self-hosted runners. The PR-oriented workflows receive no secrets and run
on fork pull requests without waiting for copy-pr-bot. Codex Security release
qualification is the exception: it runs only for maintainer-created
pre-release tags and receives a scoped NVIDIA Inference API key for the scan
step. Scanner jobs request `security-events: write` to publish SARIF to Code
Scanning. GitHub permits Code Scanning uploads from `pull_request` runs even
when fork and Dependabot contexts receive a read-only `GITHUB_TOKEN`, so those
scanners upload results directly:

- `Workflow Security Reports` runs Actionlint and Zizmor. Actionlint reports
workflow syntax and expression findings. Zizmor reports only High severity,
Expand All @@ -50,6 +52,20 @@ results directly and also retain report artifacts:
E2E test code are excluded. It runs nightly on `main`, remains manually
dispatchable for diagnostics, uploads results to Code Scanning, and retains
workflow artifacts.
- `Codex Security Release Qualification` analyzes each `vX.Y.Z-pre.N`
candidate against the previous stable release. Every candidate in a release
train therefore rescans the cumulative stable-to-candidate diff. It calls
`https://inference-api.nvidia.com/v1` with
`openai/openai/gpt-5.6-sol` at medium reasoning effort. The
`CODEX_SECURITY_API_KEY` secret must contain an API key authorized for that
NVIDIA endpoint. Results are uploaded against the candidate commit on `main`
under a category shared by the train, for example
`codex-security/v0.1.1`, so later candidates replace earlier analyses. The
slash-qualified NVIDIA model identifier prevents Codex Security 0.1.24 from
enforcing `--max-cost`, so the workflow relies on its timeout, serialized
concurrency, and the inference account's spend controls. Raw reports are not
retained as workflow artifacts. Pre-release creation and stable-promotion
enforcement remain part of RFC 0014 and are not implemented by this workflow.

Findings do not fail these workflows. Tool startup, configuration, build, and
analysis failures still fail so a broken scanner cannot appear healthy. The
Expand Down Expand Up @@ -187,6 +203,7 @@ The bot's full administrator documentation is internal to NVIDIA. The only comma
| `.github/workflows/workflow-security.yml` | Runs informational Actionlint and High-severity Zizmor reports on GitHub-hosted runners. |
| `.github/workflows/dependency-review.yml` | Reports dependency changes when GitHub Dependency Graph is available; otherwise publishes a neutral warning. |
| `.github/workflows/codeql.yml` | Runs nightly informational CodeQL analysis on `main` for Rust and the Go, Python, and TypeScript SDKs and retains SARIF artifacts. |
| `.github/workflows/codex-security.yml` | Scans the cumulative diff from the previous stable release to each pre-release candidate and publishes train-scoped SARIF on `main`. |

## Release workflows

Expand All @@ -195,7 +212,7 @@ These workflows run after merge to publish dev/tagged artifacts and verify them.
| File | Role |
|---|---|
| `.github/workflows/release-dev.yml` | Publishes the rolling `dev` build on every push to `main`. Builds gateway/supervisor images and binaries, packages, wheels, and pushes the Helm chart as `oci://ghcr.io/nvidia/openshell/helm-chart:0.0.0-dev` (plus an immutable `0.0.0-dev.<sha>` pin). Also dispatchable manually. |
| `.github/workflows/release-tag.yml` | Publishes a tagged public release. |
| `.github/workflows/release-tag.yml` | Publishes a tagged stable release. Its automatic tag trigger excludes `-pre.*`; manual dispatch remains maintainer-controlled. |
| `.github/workflows/release-canary.yml` | Smoke-tests published artifacts on `macos`, `ubuntu`, `fedora`, and `kubernetes` (kind + Helm) runners. Triggers automatically when `Release Dev` succeeds, and via `workflow_dispatch` on any branch (`gh workflow run release-canary.yml --ref <branch>`). The `kubernetes` job pins to `0.0.0-dev` artifacts; the other jobs install the latest tagged release via `install.sh`. See the `test-release-canary` skill for the manual-dispatch playbook and local kind reproduction. |

## Required status contexts
Expand Down
Loading
Loading