diff --git a/.githooks/pre-push b/.githooks/pre-push
index 0b8393fbf..0e470e426 100755
--- a/.githooks/pre-push
+++ b/.githooks/pre-push
@@ -15,6 +15,7 @@ REMOTE_URL="${2:-}"
NULL_SHA="0000000000000000000000000000000000000000"
WARNINGS=()
+REQUIRES_PREFLIGHT=0
warn() {
WARNINGS+=("$1")
@@ -127,8 +128,27 @@ while read -r local_ref local_sha remote_ref remote_sha; do
if [ -n "$maintainer_changes" ]; then
warn "Push changes maintainer-owned infrastructure paths; confirm reviewer coverage."
fi
+
+ if git diff --quiet "$review_range" -- \
+ '.github/workflows/**' \
+ '.github/scripts/**' \
+ '.githooks/**' \
+ 'Dockerfile' \
+ 'Dockerfile.*'; then
+ :
+ else
+ REQUIRES_PREFLIGHT=1
+ fi
done
+if [ "$REQUIRES_PREFLIGHT" -eq 1 ]; then
+ echo "Running required pre-push security gate for workflow, hook, script, or container changes." >&2
+ if ! .github/scripts/preflight-safety-checks.sh --require-tools; then
+ echo "[FAIL] Pre-push security gate failed." >&2
+ exit 1
+ fi
+fi
+
if [ "${#WARNINGS[@]}" -eq 0 ]; then
exit 0
fi
diff --git a/.github/instructions/workflow-governance.instructions.md b/.github/instructions/workflow-governance.instructions.md
index 9990f5d6e..b7fa733f7 100644
--- a/.github/instructions/workflow-governance.instructions.md
+++ b/.github/instructions/workflow-governance.instructions.md
@@ -39,6 +39,10 @@ run: |
source .github/scripts/sanitize-sed.sh
```
+The blocking pre-flight and risk gates enforce the first three lines of this
+prologue in order for every new or modified Bash `run:` block. The sanitizer
+remains mandatory before writing to `GITHUB_STEP_SUMMARY` or `GITHUB_OUTPUT`.
+
PowerShell-only workflows and jobs do not need `BASH_ENV`. Use an explicit
PowerShell shell on each step or `defaults.run.shell` at job/workflow scope.
diff --git a/.github/scripts/check-workflow-bash-prologue.py b/.github/scripts/check-workflow-bash-prologue.py
new file mode 100644
index 000000000..0f8b55841
--- /dev/null
+++ b/.github/scripts/check-workflow-bash-prologue.py
@@ -0,0 +1,247 @@
+#!/usr/bin/env python3
+###############################################################
+#
+# Copyright (c) 2026 International Color Consortium.
+# All rights reserved.
+# https://color.org
+#
+# Intent: Enforce the required Bash workflow security prologue.
+#
+###############################################################
+"""Reject changed Bash workflow steps that omit credential and token hardening."""
+
+import argparse
+import subprocess
+import sys
+
+import yaml
+from yaml.nodes import MappingNode, SequenceNode
+
+
+REQUIRED_PROLOGUE = (
+ "set -euo pipefail",
+ 'git config --global credential.helper ""',
+ "unset GITHUB_TOKEN || true",
+)
+
+
+def as_mapping(value):
+ return value if isinstance(value, dict) else {}
+
+
+def configured_shell(workflow, job, step):
+ for owner in (step, job, workflow):
+ shell = owner.get("shell")
+ if shell:
+ return str(shell)
+ defaults = as_mapping(owner.get("defaults"))
+ run_defaults = as_mapping(defaults.get("run"))
+ shell = run_defaults.get("shell")
+ if shell:
+ return str(shell)
+ return ""
+
+
+def is_bash_step(workflow, job, step):
+ shell = configured_shell(workflow, job, step).lower()
+ if shell:
+ return "bash" in shell
+
+ runner = str(job.get("runs-on", "")).lower()
+ return "windows" not in runner
+
+
+def executable_lines(run):
+ return [
+ (number, line.strip())
+ for number, line in enumerate(str(run).splitlines(), start=1)
+ if line.strip() and not line.lstrip().startswith("#")
+ ]
+
+
+def prologue_issues(run):
+ lines = executable_lines(run)
+ issues = []
+
+ for index, required in enumerate(REQUIRED_PROLOGUE):
+ if index >= len(lines) or lines[index][1] != required:
+ found = lines[index][1] if index < len(lines) else "end of run block"
+ issues.append(f"expected `{required}` before `{found}`")
+
+ return issues
+
+
+def changed_lines(path, base_ref):
+ commands = (
+ ("git", "diff", "--unified=0", f"{base_ref}...HEAD", "--", path),
+ ("git", "diff", "--cached", "--unified=0", "--", path),
+ ("git", "diff", "--unified=0", "--", path),
+ )
+ lines = set()
+
+ for command in commands:
+ result = subprocess.run(command, check=False, capture_output=True, text=True)
+ for line in result.stdout.splitlines():
+ if not line.startswith("@@"):
+ continue
+ marker = line.split("+", 1)[1].split(" ", 1)[0]
+ start, separator, count = marker.partition(",")
+ line_start = int(start)
+ line_count = int(count) if separator else 1
+ if line_count:
+ lines.update(range(line_start, line_start + line_count))
+ else:
+ lines.add(line_start)
+
+ if lines:
+ return lines
+
+ tracked = subprocess.run(
+ ("git", "ls-files", "--error-unmatch", "--", path),
+ check=False,
+ capture_output=True,
+ text=True,
+ )
+ if tracked.returncode:
+ with open(path, "r", encoding="utf-8") as handle:
+ return set(range(1, len(handle.readlines()) + 1))
+ return lines
+
+
+def mapping_value(node, key):
+ if not isinstance(node, MappingNode):
+ return None
+ for key_node, value_node in node.value:
+ if key_node.value == key:
+ return value_node
+ return None
+
+
+def step_line_ranges(path):
+ with open(path, "r", encoding="utf-8") as handle:
+ root = yaml.compose(handle)
+ jobs = mapping_value(root, "jobs")
+ if not isinstance(jobs, MappingNode):
+ return {}
+
+ ranges = {}
+ for job_name, job_node in jobs.value:
+ steps = mapping_value(job_node, "steps")
+ if not isinstance(steps, SequenceNode):
+ continue
+ for index, step in enumerate(steps.value, start=1):
+ ranges[(str(job_name.value), index)] = (
+ step.start_mark.line + 1,
+ step.end_mark.line + 1,
+ )
+ return ranges
+
+
+def check_workflow(path, workflow, changed=None, ranges=None):
+ findings = []
+ jobs = as_mapping(workflow.get("jobs"))
+
+ for job_name, job_value in jobs.items():
+ job = as_mapping(job_value)
+ steps = job.get("steps", [])
+ if not isinstance(steps, list):
+ continue
+
+ for index, step_value in enumerate(steps, start=1):
+ step = as_mapping(step_value)
+ if "run" not in step or not is_bash_step(workflow, job, step):
+ continue
+ if changed is not None:
+ start, end = ranges.get((str(job_name), index), (0, 0))
+ if not any(start <= line <= end for line in changed):
+ continue
+
+ step_name = str(step.get("name", f"step {index}"))
+ for issue in prologue_issues(step["run"]):
+ findings.append(f"{path}: job {job_name}, step {index} ({step_name}): {issue}")
+
+ return findings
+
+
+def run_self_test():
+ valid = {
+ "jobs": {
+ "check": {
+ "runs-on": "ubuntu-latest",
+ "steps": [{"run": "\n".join(REQUIRED_PROLOGUE)}],
+ }
+ }
+ }
+ cases = (
+ (
+ "missing-credential-helper",
+ "set -euo pipefail\nunset GITHUB_TOKEN || true",
+ ),
+ (
+ "missing-token-unset",
+ 'set -euo pipefail\ngit config --global credential.helper ""',
+ ),
+ (
+ "out-of-order-prologue",
+ 'git config --global credential.helper ""\nset -euo pipefail\nunset GITHUB_TOKEN || true',
+ ),
+ )
+
+ if check_workflow("valid.yml", valid):
+ raise AssertionError("valid fixture reported a finding")
+
+ for name, run in cases:
+ invalid = {
+ "jobs": {
+ "check": {
+ "runs-on": "ubuntu-latest",
+ "steps": [{"run": run}],
+ }
+ }
+ }
+ if not check_workflow(f"{name}.yml", invalid):
+ raise AssertionError(f"{name} fixture did not report a finding")
+
+ print("[OK] Bash prologue checker fixtures: 4")
+
+
+def main(arguments):
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--self-test", action="store_true")
+ parser.add_argument("--changed", action="store_true")
+ parser.add_argument("--base", default="HEAD")
+ parser.add_argument("workflows", nargs="*")
+ options = parser.parse_args(arguments)
+
+ if options.self_test:
+ if options.changed or options.workflows:
+ parser.error("--self-test cannot be combined with workflow paths")
+ run_self_test()
+ return 0
+
+ if not options.workflows:
+ parser.error("at least one workflow path is required")
+
+ findings = []
+ for path in options.workflows:
+ try:
+ with open(path, "r", encoding="utf-8") as handle:
+ workflow = yaml.safe_load(handle) or {}
+ except (OSError, UnicodeDecodeError, yaml.YAMLError) as error:
+ findings.append(f"{path}: unable to parse workflow: {error}")
+ continue
+
+ if not isinstance(workflow, dict):
+ findings.append(f"{path}: workflow root must be a mapping")
+ continue
+ changed = changed_lines(path, options.base) if options.changed else None
+ ranges = step_line_ranges(path) if options.changed else None
+ findings.extend(check_workflow(path, workflow, changed, ranges))
+
+ for finding in findings:
+ print(f"[FAIL] {finding}", file=sys.stderr)
+ return 1 if findings else 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main(sys.argv[1:]))
diff --git a/.github/scripts/preflight-safety-checks.sh b/.github/scripts/preflight-safety-checks.sh
index 44e1f2107..6962bb47d 100755
--- a/.github/scripts/preflight-safety-checks.sh
+++ b/.github/scripts/preflight-safety-checks.sh
@@ -96,6 +96,13 @@ run_workflow_cache_policy() {
.github/scripts/check-workflow-cache-policy.sh .github/workflows
}
+run_workflow_bash_prologue_policy() {
+ python3 .github/scripts/check-workflow-bash-prologue.py \
+ --changed \
+ --base "$base_ref" \
+ "${workflow_files[@]}"
+}
+
workflow_trigger_names() {
local wf="$1"
python3 - "$wf" <<'PY'
@@ -997,6 +1004,8 @@ for path in sys.argv[1:]:
print(f"[OK] {path}")
PY
+ run_check "workflow Bash prologue policy" run_workflow_bash_prologue_policy
+
if command -v actionlint >/dev/null 2>&1; then
run_check "actionlint" actionlint -no-color "${workflow_files[@]}"
else
@@ -1029,6 +1038,13 @@ else
echo ""
fi
+if [ -f .github/scripts/check-workflow-bash-prologue.py ]; then
+ run_check "workflow Bash prologue checker fixtures" \
+ python3 .github/scripts/check-workflow-bash-prologue.py --self-test
+else
+ skip_or_fail "check-workflow-bash-prologue.py"
+fi
+
if [ "${#script_files[@]}" -gt 0 ]; then
if command -v shellcheck >/dev/null 2>&1; then
run_check "shellcheck" shellcheck "${script_files[@]}"
diff --git a/.github/workflows/ci-afl-smoke.yml b/.github/workflows/ci-afl-smoke.yml
index cf21b5659..454598dd4 100644
--- a/.github/workflows/ci-afl-smoke.yml
+++ b/.github/workflows/ci-afl-smoke.yml
@@ -179,9 +179,9 @@ jobs:
TARGET_SHA: ${{ inputs.target_sha }}
run: |
set -euo pipefail
- source "$TRUSTED_SCRIPTS/sanitize-sed.sh"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ source "$TRUSTED_SCRIPTS/sanitize-sed.sh"
case "$TARGET_SHA" in
*[!0-9a-fA-F]*)
echo "ERROR: invalid target SHA: $(sanitize_line "$TARGET_SHA")" >&2
@@ -214,9 +214,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
source "$TRUSTED_SCRIPTS/sanitize-sed.sh"
echo "AFL targets: $(sanitize_line "$ICCDEV_AFL_TARGETS_INPUT")"
echo "AFL seconds: $(sanitize_line "$ICCDEV_AFL_SECONDS_INPUT")"
diff --git a/.github/workflows/ci-cfl-smoke.yml b/.github/workflows/ci-cfl-smoke.yml
index 667bb4be3..d86849642 100644
--- a/.github/workflows/ci-cfl-smoke.yml
+++ b/.github/workflows/ci-cfl-smoke.yml
@@ -148,9 +148,9 @@ jobs:
TARGET_SHA: ${{ inputs.target_sha }}
run: |
set -euo pipefail
- source "$TRUSTED_SCRIPTS/sanitize-sed.sh"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ source "$TRUSTED_SCRIPTS/sanitize-sed.sh"
case "$TARGET_SHA" in
*[!0-9a-fA-F]*)
echo "ERROR: invalid target SHA: $(sanitize_line "$TARGET_SHA")" >&2
diff --git a/.github/workflows/ci-docker-pr.yml b/.github/workflows/ci-docker-pr.yml
index c82cc7039..dca1c4990 100644
--- a/.github/workflows/ci-docker-pr.yml
+++ b/.github/workflows/ci-docker-pr.yml
@@ -57,9 +57,9 @@ jobs:
TARGET_SHA: ${{ inputs.target_sha }}
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
case "$TARGET_SHA" in
*[!0-9a-fA-F]*)
@@ -113,9 +113,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
case "$TARGET_SHA" in
*[!0-9a-fA-F]*)
@@ -161,6 +161,8 @@ jobs:
docker run --rm "$TEST_IMAGE" bash -lc '
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
command -v git gh clang clang++ gcc g++ cmake make realpath llvm-symbolizer
command -v afl-fuzz afl-showmap iccdev-fuzz-env
command -v jq curl shellcheck llvm-cov llvm-profdata file
@@ -216,6 +218,8 @@ jobs:
-e "WARNING_POLICY=${WARNING_POLICY}" \
"$TEST_IMAGE" bash -lc '
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
work="$(mktemp -d)"
source_dir="$work/iccDEV"
mkdir -p "$source_dir"
diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml
index 2d27bf03f..2f5123eb2 100644
--- a/.github/workflows/ci-docker.yml
+++ b/.github/workflows/ci-docker.yml
@@ -388,9 +388,9 @@ jobs:
IMAGE_REF: ${{ steps.image.outputs.name }}@${{ steps.build-push.outputs.digest }}
run: |
set -euo pipefail
- source .github/scripts/sanitize-sed.sh
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ source .github/scripts/sanitize-sed.sh
if [ "$PUBLISH_IMAGE" = "true" ]; then
TEST_IMAGE="${IMAGE_REF}"
docker pull "${IMAGE_REF}"
@@ -486,9 +486,9 @@ jobs:
IMAGE_REF: ${{ steps.image.outputs.name }}@${{ steps.build-push.outputs.digest }}
run: |
set -euo pipefail
- source .github/scripts/sanitize-sed.sh
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ source .github/scripts/sanitize-sed.sh
if [ "$PUBLISH_IMAGE" = "true" ]; then
TEST_IMAGE="${IMAGE_REF}"
docker pull "${IMAGE_REF}"
@@ -524,9 +524,9 @@ jobs:
IMAGE_REF: ${{ steps.image.outputs.name }}@${{ steps.build-push.outputs.digest }}
run: |
set -euo pipefail
- source .github/scripts/sanitize-sed.sh
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ source .github/scripts/sanitize-sed.sh
if [ "$PUBLISH_IMAGE" = "true" ]; then
TEST_IMAGE="${IMAGE_REF}"
docker pull "${IMAGE_REF}"
@@ -586,6 +586,8 @@ jobs:
docker run --rm "$TEST_IMAGE" bash -lc '
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
command -v git gh clang clang++ gcc g++ cmake make realpath afl-fuzz afl-showmap llvm-symbolizer
command -v clang-tidy cppcheck scan-build valgrind gdb gdbserver lldb lld ld.lld lcov gcovr jq curl shellcheck
command -v llvm-cov llvm-profdata file strace
@@ -643,6 +645,8 @@ jobs:
docker run --rm "$TEST_IMAGE" bash -lc '
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
test "$PWD" = /workspace/iccDEV
test -d .git
test -f IccProfLib/IccProfile.cpp
@@ -912,6 +916,7 @@ jobs:
run: |
set -euo pipefail
git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
source .github/scripts/sanitize-sed.sh
ORG="InternationalColorConsortium"
diff --git a/.github/workflows/ci-iccdev-tool-tests.yml b/.github/workflows/ci-iccdev-tool-tests.yml
index b6ad2a958..34b8d921e 100644
--- a/.github/workflows/ci-iccdev-tool-tests.yml
+++ b/.github/workflows/ci-iccdev-tool-tests.yml
@@ -271,9 +271,9 @@ jobs:
WORKFLOW_SHA: ${{ inputs.target_sha || github.event.pull_request.head.sha || github.sha }}
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
echo "Ref: ${WORKFLOW_REF}"
echo "Commit: ${WORKFLOW_SHA}"
actual_sha="$(git rev-parse HEAD)"
@@ -956,9 +956,9 @@ jobs:
DEBIAN_FRONTEND: noninteractive
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
bash .github/scripts/ci-safe-apt-update.sh
sudo apt-get install -y --no-install-recommends \
build-essential cmake \
diff --git a/.github/workflows/ci-issue-1948-segmented-curve-repro.yml b/.github/workflows/ci-issue-1948-segmented-curve-repro.yml
index 4c561396e..6e90784e4 100644
--- a/.github/workflows/ci-issue-1948-segmented-curve-repro.yml
+++ b/.github/workflows/ci-issue-1948-segmented-curve-repro.yml
@@ -223,6 +223,8 @@ jobs:
- name: Install clang and build dependencies
run: |
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
apt-get update -qq
# llvm-N is not optional padding: it carries llvm-ar and llvm-ranlib,
# and without them CMake's check_ipo_supported probe fails to archive
diff --git a/.github/workflows/ci-latest-release.yml b/.github/workflows/ci-latest-release.yml
index c8cb547d3..d11dc84e1 100644
--- a/.github/workflows/ci-latest-release.yml
+++ b/.github/workflows/ci-latest-release.yml
@@ -86,9 +86,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
export DEBIAN_FRONTEND=noninteractive
bash .github/scripts/ci-safe-apt-update.sh
sudo apt-get \
@@ -106,9 +106,9 @@ jobs:
MATRIX_COMPILER: ${{ matrix.compiler }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
if [ "${MATRIX_COMPILER}" = "gcc" ]; then
echo "CC=gcc" >> "$GITHUB_ENV"
echo "CXX=g++" >> "$GITHUB_ENV"
@@ -122,9 +122,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
source .github/scripts/sanitize-sed.sh
{
echo "Compiler Version:"
@@ -139,9 +139,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
cd Build
cmake -DCMAKE_INSTALL_PREFIX="$HOME/.local" \
-DCMAKE_BUILD_TYPE=Release \
@@ -152,9 +152,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
cd Build
make -j"$(nproc)"
- name: Verify CMake Cache
@@ -163,9 +163,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
if test -f Build/CMakeCache.txt; then
echo "[OK] Build OK" | tee -a "$GITHUB_STEP_SUMMARY"
else
@@ -178,9 +178,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
stage="staging/iccDEV-Testing"
mkdir -p "$stage"
# 1. Copy Testing contents (exclude Fuzzing)
@@ -270,9 +270,9 @@ jobs:
MATRIX_COMPILER: ${{ matrix.compiler }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
{
echo "### Linux Build Summary (${MATRIX_COMPILER})"
echo "- Build Directory: Build/"
@@ -296,9 +296,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
echo "Installing Homebrew dependencies..."
packages=(libpng nlohmann-json libxml2 wxwidgets libtiff jpeg-turbo)
missing=()
@@ -320,9 +320,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
echo "Setting up CMake build configuration..."
cd Build
sudo rm -rf /Library/Frameworks/Mono.framework/Headers/png.h
@@ -346,9 +346,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
echo "Starting build process..."
cd Build
make -j"$(sysctl -n hw.ncpu)"
@@ -360,9 +360,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
stage="staging/iccDEV-Testing"
mkdir -p "$stage"
# 1. Copy Testing contents (exclude Fuzzing)
@@ -491,9 +491,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
{
echo "### macOS Build Summary"
echo "- Build Directory: Build/"
@@ -526,10 +526,10 @@ jobs:
env:
POWERSHELL_TELEMETRY_OPTOUT: "1"
run: |
- git config --global credential.helper ""
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
+ git config --global credential.helper ""
# --- Disable telemetry sources (pwsh / dotnet / gh) ---
$env:POWERSHELL_TELEMETRY_OPTOUT = "1"
@@ -618,11 +618,11 @@ jobs:
- name: Install dependencies and build
shell: pwsh -NoProfile -NoLogo -NonInteractive -Command {0}
run: |
- git config --global credential.helper ""
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
$ProgressPreference = 'SilentlyContinue'
+ git config --global credential.helper ""
if (Test-Path Env:GITHUB_TOKEN) {
Remove-Item Env:GITHUB_TOKEN -ErrorAction SilentlyContinue
}
@@ -910,9 +910,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
rm -rf emsdk
git init emsdk
git -C emsdk remote add origin https://github.com/emscripten-core/emsdk.git
@@ -1729,9 +1729,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
source .github/scripts/sanitize-sed.sh
bash .github/scripts/ci-safe-apt-update.sh
@@ -1797,9 +1797,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
mkdir -p release-assets
@@ -1838,9 +1838,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
SANITIZER="$GITHUB_WORKSPACE/.github/scripts/sanitize-sed.sh"
if [[ -f "$SANITIZER" ]]; then
@@ -1908,9 +1908,9 @@ jobs:
GH_RUN_ID: ${{ github.run_id }}
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
release_tag="ci-latest-${GH_RUN_ID}-${GITHUB_RUN_ATTEMPT:-1}"
@@ -1974,9 +1974,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
release_tag="ci-latest-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT:-1}"
{
echo "### Release Summary"
diff --git a/.github/workflows/ci-pr-action.yml b/.github/workflows/ci-pr-action.yml
index 0bbabbd15..8889890be 100644
--- a/.github/workflows/ci-pr-action.yml
+++ b/.github/workflows/ci-pr-action.yml
@@ -113,6 +113,7 @@ jobs:
fast_lane: ${{ steps.diffcheck.outputs.fast_lane }}
include_windows: ${{ steps.diffcheck.outputs.include_windows }}
ctest_recent_limit: ${{ steps.diffcheck.outputs.ctest_recent_limit }}
+ ctest_mode: ${{ steps.diffcheck.outputs.ctest_mode }}
warning_policy: ${{ steps.diffcheck.outputs.warning_policy }}
target_sha: ${{ steps.diffcheck.outputs.target_sha }}
target_repository: ${{ steps.diffcheck.outputs.target_repository }}
@@ -143,8 +144,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
- name: Check for source changes
id: diffcheck
@@ -166,9 +168,9 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
-
- git config --add safe.directory "$PWD"
+ git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
source "$GITHUB_WORKSPACE/base/.github/scripts/sanitize-sed.sh"
ci_scope="${CI_SCOPE:-auto}"
@@ -179,6 +181,11 @@ jobs:
include_windows=true
ctest_recent_limit=0
warning_policy=fail
+ # Default to the same full CTest surface ci-regression-checks runs,
+ # so a scope resolving ctest_recent_limit=0 ("run all selected
+ # tests") does not silently diverge by excluding slow/calculator
+ # labels. Only the fast-lane scope narrows this below.
+ ctest_mode=full
case "$ci_scope" in
auto|full|source|governance|docs|fast-lane)
@@ -221,6 +228,7 @@ jobs:
write_github_output fast_lane "$fast_lane"
write_github_output include_windows "$include_windows"
write_github_output ctest_recent_limit "$ctest_recent_limit"
+ write_github_output ctest_mode "$ctest_mode"
write_github_output warning_policy "$warning_policy"
write_github_output target_sha "$head_sha"
write_github_output target_repository "$target_repository"
@@ -283,6 +291,7 @@ jobs:
ci_scope=fast-lane
include_windows=false
ctest_recent_limit=1
+ ctest_mode=fast
warning_policy=fail
}
@@ -315,6 +324,7 @@ jobs:
full|source)
include_windows=true
ctest_recent_limit=0
+ ctest_mode=full
warning_policy=fail
;;
fast-lane)
@@ -468,9 +478,9 @@ jobs:
DOCS_ONLY: ${{ steps.diffcheck.outputs.docs_only }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# --- load trusted canonical sanitizers from the checked-out base ---
TRUSTED_SANITIZER="$GITHUB_WORKSPACE/base/.github/scripts/sanitize-sed.sh"
@@ -578,8 +588,9 @@ jobs:
DOCS_ONLY: ${{ needs.detect-src.outputs.docs_only }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# Load canonical sanitizers from trusted checkout
TRUSTED_SANITIZER="$GITHUB_WORKSPACE/base/.github/scripts/sanitize-sed.sh"
if [[ -f "$TRUSTED_SANITIZER" ]]; then
@@ -642,9 +653,10 @@ jobs:
DOCS_ONLY: ${{ needs.detect-src.outputs.docs_only || 'false' }}
run: |
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
git config --add safe.directory "$PWD"
- git config --global credential.helper ""
# load trusted canonical sanitizers
TRUSTED_SANITIZER="$GITHUB_WORKSPACE/base/.github/scripts/sanitize-sed.sh"
@@ -715,6 +727,7 @@ jobs:
fast-lane: ${{ steps.v.outputs.fast_lane }}
include-windows: ${{ steps.v.outputs.include_windows }}
ctest-recent-limit: ${{ steps.v.outputs.ctest_recent_limit }}
+ ctest-mode: ${{ steps.v.outputs.ctest_mode }}
warning-policy: ${{ steps.v.outputs.warning_policy }}
steps:
@@ -736,6 +749,7 @@ jobs:
FAST_LANE: ${{ needs.detect-src.outputs.fast_lane || 'false' }}
INCLUDE_WINDOWS: ${{ needs.detect-src.outputs.include_windows || 'true' }}
CTEST_RECENT_LIMIT: ${{ needs.detect-src.outputs.ctest_recent_limit || '0' }}
+ CTEST_MODE: ${{ needs.detect-src.outputs.ctest_mode || 'full' }}
WARNING_POLICY: ${{ needs.detect-src.outputs.warning_policy || 'fail' }}
run: |
set -euo pipefail
@@ -748,7 +762,7 @@ jobs:
local value="$2"
case "$key" in
- regression_image_tag|fast_lane|include_windows|ctest_recent_limit|warning_policy) ;;
+ regression_image_tag|fast_lane|include_windows|ctest_recent_limit|ctest_mode|warning_policy) ;;
*)
echo "Invalid output key: $key" >&2
exit 1
@@ -768,6 +782,7 @@ jobs:
write_github_output fast_lane "$FAST_LANE"
write_github_output include_windows "$INCLUDE_WINDOWS"
write_github_output ctest_recent_limit "$CTEST_RECENT_LIMIT"
+ write_github_output ctest_mode "$CTEST_MODE"
write_github_output warning_policy "$WARNING_POLICY"
risk-gate:
@@ -799,7 +814,7 @@ jobs:
with:
regression_image_tag: ${{ needs.validate-inputs.outputs.regression-image-tag }}
tool_build_type: Debug
- ctest_mode: fast
+ ctest_mode: ${{ needs.validate-inputs.outputs.ctest-mode }}
ctest_recent_limit: ${{ needs.validate-inputs.outputs.ctest-recent-limit }}
warning_policy: ${{ needs.validate-inputs.outputs.warning-policy }}
target_sha: ${{ needs.detect-src.outputs.target_sha }}
@@ -881,8 +896,9 @@ jobs:
DOCKER_RESULT: ${{ needs['docker-ci'].result }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# load canonical sanitizers from trusted checkout
TRUSTED_SANITIZER="$GITHUB_WORKSPACE/base/.github/scripts/sanitize-sed.sh"
diff --git a/.github/workflows/ci-pr-gcc15.yml b/.github/workflows/ci-pr-gcc15.yml
index e07ae2134..7c6b05612 100644
--- a/.github/workflows/ci-pr-gcc15.yml
+++ b/.github/workflows/ci-pr-gcc15.yml
@@ -66,9 +66,9 @@ jobs:
# preflight: allow-codeql-actions reason=readonly-build-target-checkout
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
source "$GITHUB_WORKSPACE/trusted-base/.github/scripts/sanitize-sed.sh"
test "$(git rev-parse HEAD)" = "$TARGET_SHA"
diff --git a/.github/workflows/ci-pr-lint.yml b/.github/workflows/ci-pr-lint.yml
index 5633906cf..ce2900111 100644
--- a/.github/workflows/ci-pr-lint.yml
+++ b/.github/workflows/ci-pr-lint.yml
@@ -113,9 +113,9 @@ jobs:
- name: Validate lint inputs
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# shellcheck disable=SC1091
source trusted/.github/scripts/sanitize-sed.sh
@@ -150,9 +150,9 @@ jobs:
- name: Install lint dependencies
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# shellcheck disable=SC1091
source trusted/.github/scripts/sanitize-sed.sh
@@ -182,9 +182,9 @@ jobs:
PR_BASE_REF: ${{ github.base_ref || 'master' }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# shellcheck disable=SC1091
source trusted/.github/scripts/sanitize-sed.sh
@@ -237,9 +237,9 @@ jobs:
CXX: clang++
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# shellcheck disable=SC1091
source trusted/.github/scripts/sanitize-sed.sh
@@ -263,9 +263,9 @@ jobs:
if: steps.files.outputs.file_count != '0' && env.RUN_CPPCHECK_INPUT == 'true'
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# shellcheck disable=SC1091
source trusted/.github/scripts/sanitize-sed.sh
@@ -306,9 +306,9 @@ jobs:
if: steps.files.outputs.file_count != '0' && env.RUN_CLANG_TIDY_INPUT == 'true'
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# shellcheck disable=SC1091
source trusted/.github/scripts/sanitize-sed.sh
@@ -333,9 +333,9 @@ jobs:
SELECTED_LINT_SCOPE: ${{ steps.files.outputs.lint_scope || 'unknown' }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
# shellcheck disable=SC1091
source trusted/.github/scripts/sanitize-sed.sh
diff --git a/.github/workflows/ci-pr-risk-security-analysis.yml b/.github/workflows/ci-pr-risk-security-analysis.yml
index a1cc6682c..062686eaa 100644
--- a/.github/workflows/ci-pr-risk-security-analysis.yml
+++ b/.github/workflows/ci-pr-risk-security-analysis.yml
@@ -112,6 +112,7 @@ jobs:
ANALYSIS_TARGET: ${{ github.event.pull_request.number && 'Pull request' || inputs.analysis_target || 'Current branch workflows' }}
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number || '' }}
GIT_REF: ${{ github.event.pull_request.head.sha || inputs.git_ref || github.ref }}
+ BASE_SHA: ${{ github.event.pull_request.base.sha || github.sha }}
SEVERITY_THRESHOLD: ${{ inputs.severity_threshold || 'HIGH' }}
FAIL_ON_FINDINGS: ${{ github.event_name == 'pull_request' && 'true' || inputs.fail_on_findings && 'true' || 'false' }}
SCAN_ROOT: ${{ github.workspace }}/target
@@ -467,6 +468,78 @@ jobs:
echo "" >> "$RISK_REPORT_PATH"
exit 1
+ - name: "1c. Bash Prologue Governance Audit"
+ if: always()
+ env:
+ BASH_ENV: /dev/null
+ # preflight: allow-codeql-actions reason=readonly-target-analysis-checkout
+ run: |
+ set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
+
+ cd "$SCAN_ROOT"
+ SANITIZER="$TRUSTED_SCRIPTS/sanitize-sed.sh"
+ if [[ -f "$SANITIZER" ]]; then
+ # shellcheck disable=SC1090
+ source "$SANITIZER"
+ else
+ sanitize_line() { printf '%s' "$1"; }
+ fi
+
+ echo "## 1c. Bash Prologue Governance Audit" >> "$RISK_REPORT_PATH"
+ echo "" >> "$RISK_REPORT_PATH"
+
+ checker="$TRUSTED_SCRIPTS/check-workflow-bash-prologue.py"
+ if [ ! -x "$checker" ]; then
+ echo "[WARN] Trusted base lacks the Bash prologue checker; enforcement begins after this bootstrap change merges." >> "$RISK_REPORT_PATH"
+ exit 0
+ fi
+
+ mapfile -t workflow_files < <(
+ find .github/workflows -maxdepth 1 -type f \
+ \( -name '*.yml' -o -name '*.yaml' \) | sort
+ )
+ if [ "${#workflow_files[@]}" -eq 0 ]; then
+ echo "[HIGH] Bash prologue policy violation: no workflow files found" >> "$RISK_REPORT_PATH"
+ exit 1
+ fi
+
+ mapfile -t changed_workflows < <(
+ git diff --name-only --diff-filter=ACMRT "$BASE_SHA"...HEAD -- .github/workflows |
+ awk '/\.ya?ml$/'
+ )
+ if [ "${#changed_workflows[@]}" -eq 0 ]; then
+ echo "[OK] No changed workflow files require Bash prologue validation" >> "$RISK_REPORT_PATH"
+ echo "" >> "$RISK_REPORT_PATH"
+ exit 0
+ fi
+
+ policy_log="$(mktemp)"
+ set +e
+ python3 "$checker" --changed --base "$BASE_SHA" "${changed_workflows[@]}" >"$policy_log" 2>&1
+ policy_status=$?
+ set -e
+
+ if [ "$policy_status" -eq 0 ]; then
+ echo "[OK] All Bash workflow steps have the required security prologue" >> "$RISK_REPORT_PATH"
+ echo "" >> "$RISK_REPORT_PATH"
+ exit 0
+ fi
+
+ echo "[HIGH] Bash prologue policy violation detected" >> "$RISK_REPORT_PATH"
+ echo "" >> "$RISK_REPORT_PATH"
+ echo "Bash prologue findings
" >> "$RISK_REPORT_PATH"
+ echo "" >> "$RISK_REPORT_PATH"
+ while IFS= read -r line; do
+ [ -n "$line" ] || continue
+ echo "- \`$(sanitize_line "$line")\`" >> "$RISK_REPORT_PATH"
+ done < "$policy_log"
+ echo "" >> "$RISK_REPORT_PATH"
+ echo " " >> "$RISK_REPORT_PATH"
+ echo "" >> "$RISK_REPORT_PATH"
+ exit 1
+
- name: "2. Dangerous Trigger Detection"
if: always()
env:
diff --git a/.github/workflows/ci-pr-unix.yml b/.github/workflows/ci-pr-unix.yml
index 57d9f477e..49d22581e 100644
--- a/.github/workflows/ci-pr-unix.yml
+++ b/.github/workflows/ci-pr-unix.yml
@@ -135,9 +135,9 @@ jobs:
MATRIX_BUILD_TYPE: ${{ matrix.build_type }}
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
source .trusted-workflow/.github/scripts/sanitize-sed.sh
OS="${MATRIX_OS}"
@@ -171,9 +171,9 @@ jobs:
PR_OS: ${{ matrix.os }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
source .trusted-workflow/.github/scripts/sanitize-sed.sh
safe_event="$(sanitize_line "${PR_EVENT_NAME}")"
safe_base="$(sanitize_ref "${PR_BASE_REF}")"
@@ -211,9 +211,9 @@ jobs:
MATRIX_COMPILER: ${{ matrix.compiler }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
source .trusted-workflow/.github/scripts/sanitize-sed.sh
case "$MATRIX_COMPILER" in
gcc-15)
@@ -264,9 +264,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
source .trusted-workflow/.github/scripts/sanitize-sed.sh
brew install cmake llvm wxwidgets libpng libtiff libxml2 nlohmann-json jpeg-turbo
@@ -278,9 +278,9 @@ jobs:
COMPILER_VERSION: ${{ inputs.compiler-version || 'system' }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
source .trusted-workflow/.github/scripts/sanitize-sed.sh
case "$COMPILER_VERSION" in
system|gcc-15) ;;
@@ -307,9 +307,9 @@ jobs:
ENABLE_LTO: ${{ inputs.enable-lto && 'ON' || 'OFF' }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
source .trusted-workflow/.github/scripts/sanitize-sed.sh
echo "Configuring CMake project..."
mkdir -p Build
@@ -332,9 +332,9 @@ jobs:
WARNING_POLICY: ${{ inputs.warning-policy || 'warn' }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
source .trusted-workflow/.github/scripts/sanitize-sed.sh
echo "Start build..."
cd Build
@@ -417,9 +417,9 @@ jobs:
PROFILE_TEST_MODE: ${{ inputs.profile-test-mode || 'full' }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
source .trusted-workflow/.github/scripts/sanitize-sed.sh
echo "Creating profiles..."
cd Testing
@@ -470,9 +470,9 @@ jobs:
WARNING_POLICY: ${{ inputs.warning-policy || 'warn' }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
if [ ! -r .trusted-workflow/.github/scripts/sanitize-sed.sh ]; then
echo "ERROR: trusted sanitizer helper not found or not readable" >&2
exit 1
diff --git a/.github/workflows/ci-pr-wasm.yml b/.github/workflows/ci-pr-wasm.yml
index 3adbd4ee1..e5a5634a1 100644
--- a/.github/workflows/ci-pr-wasm.yml
+++ b/.github/workflows/ci-pr-wasm.yml
@@ -110,9 +110,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Install Emscripten SDK
env:
diff --git a/.github/workflows/ci-sanitizer-tests.yml b/.github/workflows/ci-sanitizer-tests.yml
index dbdf7e15d..78d845176 100644
--- a/.github/workflows/ci-sanitizer-tests.yml
+++ b/.github/workflows/ci-sanitizer-tests.yml
@@ -63,9 +63,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
# preflight: allow-pr-script-execution reason=sanitizer-under-test
- name: Verify sanitize-sed.sh exists
@@ -74,6 +74,8 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
if [ ! -r .github/scripts/sanitize-sed.sh ]; then
echo "ERROR: sanitize-sed.sh not found" >&2
exit 1
@@ -88,6 +90,8 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
bash .github/tests/test_sanitization.sh
# preflight: allow-pr-script-execution reason=sanitizer-under-test
@@ -97,6 +101,8 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
bash .github/tests/test-xss-signatures.sh
# preflight: allow-pr-script-execution reason=sanitizer-under-test
@@ -106,6 +112,8 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
bash .github/tests/test-xss-extended.sh
# preflight: allow-pr-script-execution reason=sanitizer-under-test
@@ -122,6 +130,8 @@ jobs:
SIMULATED_HEAD_REF_HEX: "666561747572652ff09fa496f09fa69e2d68696464656e2d6368617273"
run: |
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
source .github/scripts/sanitize-sed.sh
SIMULATED_HEAD_REF="$(printf '%s' "${SIMULATED_HEAD_REF_HEX}" | xxd -r -p)"
@@ -197,6 +207,8 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
+ git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
if [ ! -r "$TRUSTED_SCRIPTS/sanitize-sed.sh" ]; then
echo "sanitize-sed.sh missing - cannot generate summary" >&2
exit 0
diff --git a/.github/workflows/ci-vcpkg-ports.yml b/.github/workflows/ci-vcpkg-ports.yml
index b0c2c1008..92eb58c92 100644
--- a/.github/workflows/ci-vcpkg-ports.yml
+++ b/.github/workflows/ci-vcpkg-ports.yml
@@ -65,9 +65,9 @@ jobs:
BASH_ENV: /dev/null
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
# Pin vcpkg to builtin-baseline from vcpkg.json for reproducibility
git clone https://github.com/microsoft/vcpkg.git "$RUNNER_TEMP/vcpkg"
git -C "$RUNNER_TEMP/vcpkg" checkout eae1680538b86f962455c27abca2aad0dc304a4d
@@ -101,9 +101,9 @@ jobs:
VCPKG_KEEP_ENV_VARS: VCPKG_ICCDEV_SOURCE
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
TRIPLET="$([ "$RUNNER_OS" = "macOS" ] && echo "arm64-osx" || echo "x64-linux")"
if [ "$RUNNER_OS" = "Linux" ]; then
export VCPKG_FORCE_SYSTEM_BINARIES=1
@@ -176,9 +176,9 @@ jobs:
RUNNER_OS: ${{ runner.os }}
run: |
set -euo pipefail
- git config --global --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$PWD"
# Load sanitizers from trusted base checkout.
if [ -f "$TRUSTED_SCRIPTS/sanitize-sed.sh" ]; then
# shellcheck disable=SC1090
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2c29b751b..6afdd9052 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -65,9 +65,9 @@ jobs:
- name: Bootstrap pinned vcpkg
run: |
set -euo pipefail
- git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
source .github/scripts/sanitize-sed.sh
git clone https://github.com/microsoft/vcpkg.git "$RUNNER_TEMP/vcpkg"
diff --git a/.github/workflows/update-labels.yml b/.github/workflows/update-labels.yml
index 1166eddab..d22ac7074 100644
--- a/.github/workflows/update-labels.yml
+++ b/.github/workflows/update-labels.yml
@@ -68,9 +68,9 @@ jobs:
GH_REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
.github/scripts/sync-labels.sh
@@ -84,8 +84,9 @@ jobs:
EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
EVENT_PR="${EVENT_PR_NUMBER}"
@@ -143,8 +144,9 @@ jobs:
PR_LIST: ${{ steps.pr_list.outputs.prs }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
+ unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
RESULTS_FILE=$(mktemp)
PROCESSED=0
@@ -319,9 +321,9 @@ jobs:
PRS_LABELED: ${{ steps.process.outputs.labeled || '0' }}
run: |
set -euo pipefail
- git config --add safe.directory "$PWD"
git config --global credential.helper ""
unset GITHUB_TOKEN || true
+ git config --add safe.directory "$PWD"
SANITIZER=".github/scripts/sanitize-sed.sh"
if [[ -f "$SANITIZER" ]]; then
diff --git a/Dockerfile b/Dockerfile
index 914eb79a1..c444ccefb 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,7 +16,7 @@ ENV DEBIAN_FRONTEND=noninteractive
# Package versions are pinned to the digest-pinned Ubuntu base validated on master.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
- build-essential=12.12ubuntu2 \
+ build-essential=12.12ubuntu2.26.04.2 \
cmake=4.2.3-2ubuntu2 \
gcc=4:15.2.0-5ubuntu1 \
g++=4:15.2.0-5ubuntu1 \
@@ -26,7 +26,7 @@ RUN apt-get update \
libxml2-16=2.15.2+dfsg-0.1ubuntu0.1 \
libxml2-dev=2.15.2+dfsg-0.1ubuntu0.1 \
nlohmann-json3-dev=3.12.0.really.3.12.0.really.3.11.3-3build1 \
- libtiff-dev=4.7.0-3ubuntu4 \
+ libtiff-dev=4.7.0-3ubuntu5 \
libjpeg-dev=8c-2ubuntu12 \
libpng-dev=1.6.57-1 \
zlib1g-dev=1:1.3.dfsg+really1.3.1-1ubuntu3 \
@@ -84,7 +84,7 @@ LABEL org.opencontainers.image.title="iccDEV Build Container" \
RUN apt-get update && apt-get install -y --no-install-recommends \
libc6=2.43-2ubuntu2.3 \
libxml2-16=2.15.2+dfsg-0.1ubuntu0.1 \
- libtiff6=4.7.0-3ubuntu4 \
+ libtiff6=4.7.0-3ubuntu5 \
libjpeg8=8c-2ubuntu12 \
libpng16-16t64=1.6.57-1 \
libasan8=16-20260322-1ubuntu1 \
diff --git a/Dockerfile.ci-regression b/Dockerfile.ci-regression
index 34390284b..4ded7e305 100644
--- a/Dockerfile.ci-regression
+++ b/Dockerfile.ci-regression
@@ -28,14 +28,14 @@ RUN apt-get update \
afl++=4.33c-1.1ubuntu1 \
bash=5.3-2ubuntu1 \
binutils=2.46-3ubuntu2 \
- build-essential=12.12ubuntu2 \
+ build-essential=12.12ubuntu2.26.04.2 \
ca-certificates=20260601~26.04.1 \
clang-22=1:22.1.2-1ubuntu1 \
clang-tidy-22=1:22.1.2-1ubuntu1 \
clang-tools-22=1:22.1.2-1ubuntu1 \
cmake=4.2.3-2ubuntu2 \
cppcheck=2.19.0-3 \
- curl=8.18.0-1ubuntu2.3 \
+ curl=8.18.0-1ubuntu2.4 \
diffutils=1:3.12-1 \
file=1:5.46-5build2 \
g++=4:15.2.0-5ubuntu1 \
@@ -50,11 +50,11 @@ RUN apt-get update \
libclang-rt-22-dev=1:22.1.2-1ubuntu1 \
libclang-rt-21-dev=1:21.1.8-6ubuntu1 \
libjpeg-dev=8c-2ubuntu12 \
- libtiff-tools=4.7.0-3ubuntu4 \
+ libtiff-tools=4.7.0-3ubuntu5 \
liblzma-dev=5.8.3-1 \
libpng-dev=1.6.57-1 \
libssl-dev=3.5.5-1ubuntu3.3 \
- libtiff-dev=4.7.0-3ubuntu4 \
+ libtiff-dev=4.7.0-3ubuntu5 \
libwxgtk3.2-dev=3.2.9+dfsg-1 \
zlib1g=1:1.3.dfsg+really1.3.1-1ubuntu3 \
lld-22=1:22.1.2-1ubuntu1 \
diff --git a/docs/regression-container.md b/docs/regression-container.md
index 35b98d142..95c174193 100644
--- a/docs/regression-container.md
+++ b/docs/regression-container.md
@@ -425,6 +425,44 @@ Repository rules intentionally differ by branch:
deletion. Its hosted `ci-pr-action` and `ci-docker` runs are dispatched after
the push rather than configured as pre-push required contexts.
+## Apt Package Version Drift (ci-docker Failures)
+
+`Dockerfile` and `Dockerfile.ci-regression` pin exact `apt-get install`
+`package=version` strings against the digest-pinned Ubuntu base image so
+builds stay reproducible. The Ubuntu 26.04 apt archive still republishes point
+releases for the same base digest (for example a `-3ubuntu4` package becoming
+`-3ubuntu5`, or a `build-essential` metapackage gaining a distro revision
+suffix), and a stale pin then fails `apt-get install` with
+`E: Unable to satisfy dependencies` or `E: Version '' for '' was
+not found`, which surfaces as a `ci-docker` job failure with exit code `100`.
+
+Diagnose and fix a drifted pin:
+
+```bash
+# 1. Reproduce locally against the exact pinned base digest.
+docker build --no-cache -f Dockerfile -t iccdev-local-ubuntu-test .
+docker build --no-cache -f Dockerfile.ci-regression -t iccdev-local-regression-test .
+
+# 2. Regenerate current candidate versions for every pinned package in a
+# disposable container from the same base digest (replace PKGS with the
+# package list from the failing Dockerfile).
+docker run --rm ubuntu:26.04@sha256: bash -c '
+ set -euo pipefail
+ apt-get update -qq
+ for p in PKGS; do
+ v=$(apt-cache policy "$p" | awk "/Candidate:/{print \$2}")
+ echo "$p=$v"
+ done'
+```
+
+Update only the packages whose candidate version differs from the pin; do not
+relax exact pins to unpinned installs. Apply the same pin fix consistently
+across every maintained container file that shares the pin (`Dockerfile` and
+`Dockerfile.ci-regression`; `Dockerfile.mcp` intentionally tracks unpinned
+security updates and is unaffected), confirm with a clean local `docker build`,
+then carry the fix to other maintained branches per the branch-parity step
+above only when a maintainer has requested that branch be updated.
+
## Maintainer Report
Report: