diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..477178c901 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,24 @@ +# Copyright Advanced Micro Devices, Inc. +# SPDX-License-Identifier: MIT +# +# Dependabot version updates. See +# https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference + +version: 2 +updates: + - package-ecosystem: "github-actions" + # "/" covers .github/workflows; composite actions keep their own `uses:` + # pins, so .github/actions has to be listed separately to get bumped. + directory: "/" + schedule: + interval: "daily" + # Wait a week before adopting newly released action versions. + cooldown: + default-days: 7 + exclude: + - "ROCm/rocm-security-gh*" + groups: + rocm-security-gh: + patterns: ["ROCm/rocm-security-gh*"] + github-actions: + patterns: ["*"] diff --git a/.github/scan_tools_configs/bandit.yml b/.github/scan_tools_configs/bandit.yml new file mode 100644 index 0000000000..567e31a211 --- /dev/null +++ b/.github/scan_tools_configs/bandit.yml @@ -0,0 +1,22 @@ +# Copyright Advanced Micro Devices, Inc. +# SPDX-License-Identifier: MIT +# +# bandit configuration +# Reference: https://bandit.readthedocs.io/en/latest/config.html +# Local scan: bandit --recursive . --configfile .github/scan_tools_configs/bandit.yml +# +# Bandit configuration for this repository's security scans. +# +# This file defines the complete scanner policy; +# Keep repository-specific suppressions and tuning here. + +# Environment and generated-output exclusions support local scans; these +# paths are absent from clean CI checkouts. +exclude_dirs: + - .git + - .venv* + - venv* + - build + - dist + - node_modules + - __pycache__ diff --git a/.github/scan_tools_configs/gitleaks.toml b/.github/scan_tools_configs/gitleaks.toml new file mode 100644 index 0000000000..f56e42845d --- /dev/null +++ b/.github/scan_tools_configs/gitleaks.toml @@ -0,0 +1,71 @@ +# Copyright Advanced Micro Devices, Inc. +# SPDX-License-Identifier: MIT +# +# gitleaks.toml +# Reference: https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml +# Local scan: gitleaks detect --source . --config .github/scan_tools_configs/gitleaks.toml +# +# Gitleaks configuration for this repository's security scans. +# +# This file defines the repository's complete Gitleaks policy. Recurring +# exclusions belong in this file. +# +# The `[extend]` section inherits Gitleaks' built-in rules, and the +# `[[allowlists]]` below apply to every rule. +# +# Use `.gitleaksignore` for one-off finding fingerprints. Add recurring path +# or regex exclusions to `[[allowlists]]` in this file. + +title = "gitleaks config" + +[extend] +# Inherit gitleaks' built-in ruleset (rotations, AWS, GCP, Slack, ...). +# Setting this to false would mean rolling our own detections, which +# is almost never what you want. +useDefault = true + + + +# Allowlist field-vs-target reference: +# stopwords -> always matched against the SECRET value. +# regexes -> matched against `regexTarget` (default: "secret"). +# regexTarget -> "secret" | "match" | "line". +# Use "match" or "line" when the "tell" is the variable name or +# surrounding syntax, not the value itself. + +[[allowlists]] +# Allowlist by location only where a real first-party secret structurally +# can't live. Dependency lock files qualify: their contents are generated +# from a manifest, and the high-entropy strings they carry are artifact +# digests rather than credentials. Add vendored third-party trees here as +# callers bring them in, one explicit path per entry. +description = "Generated dependency lock files" +paths = [ + '''.*\.lock$''', +] + +[[allowlists]] +description = "Test fixtures using well-known dummy variable names" +# The "tell" here is the variable name on the same line, not the value +# (the value is a random-looking string by design). Match against the +# full rule match (variable + value) so we anchor on the identifier. +regexTarget = "match" +regexes = [ + '''(?i)\bINVALID_TOKEN\s*=''', + '''(?i)\bwrong_secret\s*=''', + # Explicit test-only secret identifiers + '''(?i)\btest_secret\s*=''', + '''(?i)\bdummy_secret\s*=''', + '''(?i)\bfake_secret\s*=''', + '''(?i)\bexample_secret\s*=''' +] + +[[allowlists]] +description = "Public artifact digests (variable names ending in SHA256/512/MD5)" +# SHA-256/512/MD5 hashes of public artifacts are not secrets. +regexTarget = "line" +regexes = [ + '''[A-Z][A-Z0-9_]*SHA256\s*[=:]''', + '''[A-Z][A-Z0-9_]*SHA512\s*[=:]''', + '''[A-Z][A-Z0-9_]*MD5\s*[=:]''', +] diff --git a/.github/scan_tools_configs/trivy.yml b/.github/scan_tools_configs/trivy.yml new file mode 100644 index 0000000000..c7ce17413a --- /dev/null +++ b/.github/scan_tools_configs/trivy.yml @@ -0,0 +1,23 @@ +# Copyright Advanced Micro Devices, Inc. +# SPDX-License-Identifier: MIT +# +# trivy configuration +# Reference: https://trivy.dev/latest/docs/references/configuration/config-file/ +# Local scan: trivy fs --config .github/scan_tools_configs/trivy.yml . +# +# Trivy configuration for this repository's security scans. +# +# This file defines the complete scanner policy; +# Keep repository-specific suppressions and tuning here. + +# Environment and generated-output exclusions support local scans; these +# paths are absent from clean CI checkouts. +scan: + skip-dirs: + - .git + - .venv* + - venv* + - build + - dist + - node_modules + - __pycache__ diff --git a/.github/scan_tools_configs/zizmor.yml b/.github/scan_tools_configs/zizmor.yml new file mode 100644 index 0000000000..6135169bf3 --- /dev/null +++ b/.github/scan_tools_configs/zizmor.yml @@ -0,0 +1,15 @@ +# Copyright Advanced Micro Devices, Inc. +# SPDX-License-Identifier: MIT +# +# zizmor configuration +# Reference: https://docs.zizmor.sh/configuration/ +# Local scan: zizmor --config .github/scan_tools_configs/zizmor.yml . +# +# Zizmor configuration for this repository's security scans. +# +# This file defines the complete scanner policy; +# Keep repository-specific suppressions and tuning here. +# +# Add rule-specific settings and suppressions under `rules:`. + +rules: {} diff --git a/.github/workflows/build_rocm_image.yml b/.github/workflows/build_rocm_image.yml index 2eab960f51..0d8311eda7 100644 --- a/.github/workflows/build_rocm_image.yml +++ b/.github/workflows/build_rocm_image.yml @@ -27,7 +27,7 @@ jobs: IMAGE: ghcr.io/rocm/maxtext DOCKER_BUILDKIT: "1" steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: persist-credentials: false @@ -44,9 +44,10 @@ jobs: - name: Compute image tags id: tags shell: bash + env: + SUFFIX: ${{ inputs.image_suffix }} run: | set -euo pipefail - SUFFIX="${{ inputs.image_suffix }}" { echo "nightly=rocm_jax_nightly${SUFFIX:+_${SUFFIX}}" echo "date=$(date -u +%Y-%m-%d)" @@ -61,18 +62,24 @@ jobs: - name: Build image (local tags, no push yet) shell: bash + env: + TAG_NIGHTLY: ${{ steps.tags.outputs.nightly }} + TAG_DATE: ${{ steps.tags.outputs.date }} + TAG_SHA: ${{ steps.tags.outputs.sha }} run: | set -euo pipefail - echo "Building ${IMAGE} tags: ${{ steps.tags.outputs.nightly }}, ${{ steps.tags.outputs.date }}, ${{ steps.tags.outputs.sha }}" + echo "Building ${IMAGE} tags: ${TAG_NIGHTLY}, ${TAG_DATE}, ${TAG_SHA}" docker build \ -f src/dependencies/dockerfiles/maxtext_rocm_dependencies.Dockerfile \ - -t "${IMAGE}:${{ steps.tags.outputs.nightly }}" \ - -t "${IMAGE}:${{ steps.tags.outputs.date }}" \ - -t "${IMAGE}:${{ steps.tags.outputs.sha }}" \ + -t "${IMAGE}:${TAG_NIGHTLY}" \ + -t "${IMAGE}:${TAG_DATE}" \ + -t "${IMAGE}:${TAG_SHA}" \ . - name: Smoke test the built image (on GPU) shell: bash + env: + TAG_SHA: ${{ steps.tags.outputs.sha }} run: | set -euo pipefail # Run the freshly-built image on the runner's GPUs (same device/isolation flags as CI) @@ -81,17 +88,24 @@ jobs: --device=/dev/kfd --device=/dev/dri --security-opt seccomp=unconfined \ --group-add video --shm-size 64G \ --env-file /etc/podinfo/gha-gpu-isolation-settings \ - "${IMAGE}:${{ steps.tags.outputs.sha }}" \ + "${IMAGE}:${TAG_SHA}" \ python3 -c 'import jax, transformer_engine, maxtext; d=jax.devices(); print("jax", jax.__version__, "devices:", d); assert d, "no JAX devices visible in the image"; print("transformer_engine", getattr(transformer_engine, "__version__", "?")); print("smoke test OK")' - name: Log in to GitHub Container Registry shell: bash - run: echo "${{ github.token }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin + env: + GHCR_TOKEN: ${{ github.token }} + GHCR_USER: ${{ github.actor }} + run: echo "${GHCR_TOKEN}" | docker login ghcr.io -u "${GHCR_USER}" --password-stdin - name: Push image shell: bash + env: + TAG_NIGHTLY: ${{ steps.tags.outputs.nightly }} + TAG_DATE: ${{ steps.tags.outputs.date }} + TAG_SHA: ${{ steps.tags.outputs.sha }} run: | set -euo pipefail - docker push "${IMAGE}:${{ steps.tags.outputs.nightly }}" - docker push "${IMAGE}:${{ steps.tags.outputs.date }}" - docker push "${IMAGE}:${{ steps.tags.outputs.sha }}" + docker push "${IMAGE}:${TAG_NIGHTLY}" + docker push "${IMAGE}:${TAG_DATE}" + docker push "${IMAGE}:${TAG_SHA}" diff --git a/.github/workflows/build_rocm_transformer_engine_wheel_weekly.yml b/.github/workflows/build_rocm_transformer_engine_wheel_weekly.yml index 04309f3aab..f9c82fec35 100644 --- a/.github/workflows/build_rocm_transformer_engine_wheel_weekly.yml +++ b/.github/workflows/build_rocm_transformer_engine_wheel_weekly.yml @@ -32,7 +32,9 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + with: + persist-credentials: false - name: Setup build environment (deps + venv) shell: bash diff --git a/.github/workflows/pr-security-scan.yml b/.github/workflows/pr-security-scan.yml new file mode 100644 index 0000000000..4aa71aaa15 --- /dev/null +++ b/.github/workflows/pr-security-scan.yml @@ -0,0 +1,41 @@ +# Copyright Advanced Micro Devices, Inc. +# SPDX-License-Identifier: MIT +# +# Pre-commit security gate: fast, PR-side security scanners that run on +# every pull request. Scanner selection and policy are defined by the pinned +# ROCm/rocm-security-gh `security-baseline.yml` reusable workflow. +# +# Requests human-readable reports only: findings are uploaded as a build +# artifact and printed to the job summary, never to the Security tab, so +# fork PRs (which never receive elevated tokens) behave identically to +# same-repo PRs. See the scheduled counterpart (weekly-security-scan.yml) +# for the SARIF / code-scanning upload. + +name: Security scan (PR) + +on: + pull_request: + # Spelled out the default to avoid confusion. + types: [opened, synchronize, reopened] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + security: + name: Security scan + permissions: + actions: read + contents: read + pull-requests: write + uses: ROCm/rocm-security-gh/.github/workflows/security-baseline.yml@228e62369c5d8b677215f8a112ea0c8e8119c58f # v1.0.6 + with: + report_formats: human + bandit_config_path: .github/scan_tools_configs/bandit.yml + gitleaks_config_path: .github/scan_tools_configs/gitleaks.toml + trivy_config_path: .github/scan_tools_configs/trivy.yml + zizmor_config_path: .github/scan_tools_configs/zizmor.yml diff --git a/.github/workflows/run_tests_against_package.yml b/.github/workflows/run_tests_against_package.yml index 8a0d511ea2..daea775be7 100644 --- a/.github/workflows/run_tests_against_package.yml +++ b/.github/workflows/run_tests_against_package.yml @@ -151,11 +151,11 @@ jobs: if: ${{ !inputs.maxtext_installed }} shell: bash run: | - if [ "${{ inputs.device_type }}" = "rocm" ]; then + if [ "${INPUTS_DEVICE_TYPE}" = "rocm" ]; then python3 -m pip install -U uv fi # ROCm: inherit the image's TheRock ROCm SDK (rocm-sdk) into the venv; never install ROCm. - if [ "${{ inputs.device_type }}" = "rocm" ]; then + if [ "${INPUTS_DEVICE_TYPE}" = "rocm" ]; then python3 -m uv venv --seed --system-site-packages else python3 -m uv venv --seed @@ -163,23 +163,23 @@ jobs: source .venv/bin/activate maxtext_wheel=$(ls maxtext-*-py3-none-any.whl 2>/dev/null) echo "Installing ${maxtext_wheel} for ${MAXTEXT_PACKAGE_EXTRA}..." - if [ "${{ inputs.device_type }}" = "rocm" ]; then - if [ -n "${{ inputs.requirements_file }}" ]; then - echo "Installing requirements from ${{ inputs.requirements_file }}" + if [ "${INPUTS_DEVICE_TYPE}" = "rocm" ]; then + if [ -n "${INPUTS_REQUIREMENTS_FILE}" ]; then + echo "Installing requirements from ${INPUTS_REQUIREMENTS_FILE}" # generated_requirements/ files are seed-env locks expressed as lower bounds, so # --resolution=lowest is what installs the versions they pin (the same way the # non-ROCm branch installs the wheel extras); base_requirements/ resolve normally. - case "${{ inputs.requirements_file }}" in + case "${INPUTS_REQUIREMENTS_FILE}" in */generated_requirements/*) resolution='--resolution=lowest' ;; *) resolution='' ;; esac - uv pip install ${resolution} -r "${{ inputs.requirements_file }}" + uv pip install ${resolution} -r "${INPUTS_REQUIREMENTS_FILE}" fi uv pip install "${maxtext_wheel}" --no-deps # A requirements file already carries the test/runtime deps; otherwise add the # GitHub-sourced pins (no TPU extra / scripts). The decoupled lock must not get them: # google-jetstream is one of the packages decoupled mode has to run without. - if [ -z "${{ inputs.requirements_file }}" ]; then + if [ -z "${INPUTS_REQUIREMENTS_FILE}" ]; then uv pip install -r src/dependencies/extra_deps/pre_train_github_deps.txt --no-deps fi else @@ -207,13 +207,17 @@ jobs: python3 -m pip freeze env: INPUTS_INSTALL_TORCH_CPU: ${{ inputs.install_torch_cpu }} + INPUTS_DEVICE_TYPE: ${{ inputs.device_type }} + INPUTS_REQUIREMENTS_FILE: ${{ inputs.requirements_file }} - name: Install extra pip deps if: inputs.extra_pip_deps_file != '' shell: bash + env: + INPUTS_EXTRA_PIP_DEPS_FILE: ${{ inputs.extra_pip_deps_file }} run: | source .venv/bin/activate - uv pip install -r ${{ inputs.extra_pip_deps_file }} + uv pip install -r "${INPUTS_EXTRA_PIP_DEPS_FILE}" - name: Install ROCm JAX plugin + pjrt if: ${{ inputs.device_type == 'rocm' }} diff --git a/.github/workflows/weekly-security-scan.yml b/.github/workflows/weekly-security-scan.yml new file mode 100644 index 0000000000..300cc312d3 --- /dev/null +++ b/.github/workflows/weekly-security-scan.yml @@ -0,0 +1,34 @@ +# Copyright Advanced Micro Devices, Inc. +# SPDX-License-Identifier: MIT +# +# Weekly security scan: runs on a fixed cadence and pushes SARIF findings +# to the repository's code-scanning Security tab. Complements +# `pr-security-scan.yml`, which scans only what changed in a PR and +# uploads reviewer-readable artifacts for in-review browsing. + +name: Security scan (Weekly) + +on: + # Run every Saturday at 10:00 UTC. + schedule: + - cron: "0 10 * * 6" + workflow_dispatch: + +permissions: + contents: read + +jobs: + security: + name: Security scan + # Only the job that uploads SARIF gets write access to code scanning. + permissions: + contents: read + security-events: write + uses: ROCm/rocm-security-gh/.github/workflows/security-baseline.yml@228e62369c5d8b677215f8a112ea0c8e8119c58f # v1.0.6 + with: + scan_mode: all + report_formats: sarif + bandit_config_path: .github/scan_tools_configs/bandit.yml + gitleaks_config_path: .github/scan_tools_configs/gitleaks.toml + trivy_config_path: .github/scan_tools_configs/trivy.yml + zizmor_config_path: .github/scan_tools_configs/zizmor.yml diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..cf466d848a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,15 @@ +# Security Policy + +## Reporting a Vulnerability + +**Do not open a public GitHub issue.** Report privately via one of: + +- **AMD Product Security portal:** https://www.amd.com/en/resources/product-security.html + +Please include: description and impact, steps to reproduce, and affected versions or commits. + +We aim to acknowledge reports within 1 business day. + +## Scope + +This policy covers code and configuration in this repository. For vulnerabilities in third-party dependencies, report upstream. For AMD product issues unrelated to this repo, use the [AMD Product Security portal](https://www.amd.com/en/resources/product-security.html). diff --git a/src/dependencies/dockerfiles/maxtext_rocm_dependencies.Dockerfile b/src/dependencies/dockerfiles/maxtext_rocm_dependencies.Dockerfile index c649d171e2..d771d41493 100644 --- a/src/dependencies/dockerfiles/maxtext_rocm_dependencies.Dockerfile +++ b/src/dependencies/dockerfiles/maxtext_rocm_dependencies.Dockerfile @@ -47,3 +47,11 @@ RUN --mount=type=cache,target=/root/.cache/uv \ "jax-rocm10-plugin==${ROCM_JAX_VERSION}+rocm${ROCM_SDK_VER}"; \ TE_WHL="$(ls /deps/transformer_engine-*.whl 2>/dev/null | sort | tail -n1 || true)"; \ if [ -n "${TE_WHL}" ]; then uv pip install --system --no-deps --force-reinstall "${TE_WHL}"; fi + +# Batch training/test image: no long-running service to probe. +HEALTHCHECK NONE + +# Stays root like its ROCm base image: GPU access (/dev/kfd, /dev/dri) and in-container +# installs assume it. +# trivy:ignore:DS-0002 +USER root