Skip to content

Commit 68b4f4f

Browse files
authored
stability: implement audit findings remediation plan (#38)
* stability: remediate audit findings with runtime, CI, and docs hardening Implement the validated remediation plan end-to-end: extract uploader runtimes into standalone templates, enforce a Windows PowerShell-only path, strengthen sync/uploader safety checks, expand release workflow parity, and close the findings ledger with evidence. This reduces drift between platforms and release lanes while making audit coverage and tooling validation deterministic. * stability: close post-review validation and visibility gaps Fix post-review regressions by restoring uploader runtime template parity, exporting new test/tooling artifacts for Bazel visibility, and hardening bazelw version detection so enforcement works with non-standard version output formats. This brings full //... test execution and strict findings-ledger validation back to green. * stability: enforce uploader fingerprint parity and windows policy Align uploader runtime fingerprint behavior with sync-side Starlark so API key parity checks stay deterministic across Bash and PowerShell. Remove Bash runtime Windows delegation and add regression tests that lock in PowerShell-only Windows behavior and cross-runtime fingerprint parity. * stability: resolve PR38 CI formatting and scanning blockers Format modified Starlark files to satisfy buildifier checks and remove the secret-like mock API key literal flagged during PR review. Replace regex-based Bash alphabet extraction in tests with deterministic parsing to avoid regex backtracking risk while preserving runtime parity validation. * stability: fix Windows mock server process redirection Use separate stdout and stderr redirection files in the Windows integration harness so Start-Process works reliably on GitHub Windows runners. This resolves the bazel-tests windows job failure in PR #38. * stability: fix Windows sync directory creation command Use PowerShell New-Item -Path for repository-rule directory creation so Windows fetches succeed on CI environments where -LiteralPath is not accepted for New-Item. Add a regression test that locks this command shape in the sync module. * stability: restore tests STS mapping and annotate codepaths Restore the Chainguard STS configuration to the tests repository identity and remove the audit source artifacts as requested. Add maintainer-focused documentation across changed runtime, sync, tooling, and test helpers so behavior and intent are easier to reason about during future maintenance. * stability: remove findings-ledger CI policy and tooling Drop the audit findings ledger checker from CI/release workflows and remove the helper script now that docs/audit is no longer part of the repository. Update developer docs and exports to keep policy, tooling, and workflow behavior consistent.
1 parent e9f4705 commit 68b4f4f

48 files changed

Lines changed: 5246 additions & 4247 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ jobs:
163163

164164
- name: Install Python tooling dependencies
165165
shell: bash
166-
run: python3 -m pip install -r tools/requirements.txt
166+
run: python3 -m pip install --require-hashes -r tools/requirements.txt
167167

168168
- name: Verify Python tooling tests through Bazel
169169
shell: bash
@@ -376,12 +376,16 @@ jobs:
376376

377377
- name: Install Python tooling dependencies
378378
shell: bash
379-
run: python3 -m pip install -r tools/requirements.txt
379+
run: python3 -m pip install --require-hashes -r tools/requirements.txt
380380

381381
- name: Verify core/go module versions are aligned
382382
shell: bash
383383
run: python3 tools/dev/check_module_versions.py
384384

385+
- name: Verify .bazelversion parity
386+
shell: bash
387+
run: python3 tools/dev/check_bazelversion_sync.py
388+
385389
- name: Validate integration fixture and snapshot JSON
386390
shell: bash
387391
run: |

.github/workflows/release.yml

Lines changed: 199 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@ jobs:
3131

3232
- name: Install Python tooling dependencies
3333
shell: bash
34-
run: python3 -m pip install -r tools/requirements.txt
34+
run: python3 -m pip install --require-hashes -r tools/requirements.txt
3535

3636
- name: Verify core/go module versions are aligned
3737
shell: bash
3838
run: python3 tools/dev/check_module_versions.py
3939

40+
- name: Verify .bazelversion parity
41+
shell: bash
42+
run: python3 tools/dev/check_bazelversion_sync.py
43+
4044
- name: Verify schema files are in sync
4145
shell: bash
4246
run: python3 tools/core/schemas/sync_agentless_schema.py --check
@@ -68,3 +72,197 @@ jobs:
6872
run: |
6973
echo "Release validation completed."
7074
echo "Before publishing, follow CONTRIBUTING.md release runbook steps."
75+
76+
release-hermetic:
77+
timeout-minutes: 45
78+
runs-on: ubuntu-latest
79+
steps:
80+
- name: Checkout
81+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
82+
83+
- name: Run Bazel tests (hermetic lane)
84+
timeout-minutes: 25
85+
shell: bash
86+
run: |
87+
./bazelw test //tools/... \
88+
--spawn_strategy=sandboxed \
89+
--strategy=TestRunner=sandboxed \
90+
--incompatible_strict_action_env \
91+
--sandbox_default_allow_network=false \
92+
--modify_execution_info=TestRunner=+block-network \
93+
--test_env=TZ=UTC \
94+
--test_env=LANG=C \
95+
--test_env=LC_ALL=C \
96+
--enable_runfiles
97+
98+
- name: Run Bazel tests (go companion hermetic lane)
99+
timeout-minutes: 25
100+
shell: bash
101+
run: |
102+
cd modules/go &&
103+
../../bazelw test //... \
104+
--override_module=datadog-rules-test-optimization=../.. \
105+
--spawn_strategy=sandboxed \
106+
--strategy=TestRunner=sandboxed \
107+
--incompatible_strict_action_env \
108+
--sandbox_default_allow_network=false \
109+
--modify_execution_info=TestRunner=+block-network \
110+
--test_env=TZ=UTC \
111+
--test_env=LANG=C \
112+
--test_env=LC_ALL=C \
113+
--enable_runfiles
114+
115+
release-shell-lint:
116+
timeout-minutes: 15
117+
runs-on: ubuntu-latest
118+
steps:
119+
- name: Checkout
120+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
121+
122+
- name: Set up Python
123+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
124+
with:
125+
python-version: ${{ env.PYTHON_VERSION }}
126+
127+
- name: Install shellcheck
128+
shell: bash
129+
run: |
130+
sudo apt-get update
131+
sudo apt-get install -y shellcheck
132+
133+
- name: Lint repository shell scripts
134+
shell: bash
135+
run: |
136+
shellcheck --severity=error \
137+
bazelw \
138+
examples/single_service/runtests.sh \
139+
examples/multi_service/runtests.sh \
140+
tools/tests/integration/*.sh \
141+
tools/tests/python/run_python_tools_test.sh \
142+
tools/tests/python/run_bazelw_wrapper_test.sh
143+
144+
- name: Lint uploader templates (bash parser)
145+
shell: bash
146+
run: python3 tools/dev/lint_uploader_templates.py --skip-powershell-parse
147+
148+
release-powershell-lint:
149+
timeout-minutes: 20
150+
runs-on: windows-latest
151+
steps:
152+
- name: Checkout
153+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
154+
155+
- name: Set up Python
156+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
157+
with:
158+
python-version: ${{ env.PYTHON_VERSION }}
159+
160+
- name: Install PSScriptAnalyzer
161+
shell: pwsh
162+
run: |
163+
if (-not (Get-Module -ListAvailable -Name PSScriptAnalyzer)) {
164+
if (-not (Get-PackageProvider -ListAvailable -Name NuGet -ErrorAction SilentlyContinue)) {
165+
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
166+
}
167+
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
168+
Install-Module -Name PSScriptAnalyzer -Scope CurrentUser -Force -AllowClobber
169+
}
170+
171+
- name: Lint integration PowerShell scripts
172+
shell: pwsh
173+
run: |
174+
$results = Invoke-ScriptAnalyzer -Path "tools/tests/integration/*.ps1" -Severity Error
175+
if ($results) {
176+
$results | Format-Table -AutoSize
177+
throw "PSScriptAnalyzer found lint errors."
178+
}
179+
180+
- name: Lint uploader templates (PowerShell parser)
181+
shell: pwsh
182+
run: python tools/dev/lint_uploader_templates.py --skip-shellcheck
183+
184+
release-gofmt-check:
185+
timeout-minutes: 10
186+
runs-on: ubuntu-latest
187+
steps:
188+
- name: Checkout
189+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
190+
191+
- name: Verify Go files are gofmt formatted
192+
shell: bash
193+
run: |
194+
mapfile -t go_files < <(git ls-files '*.go')
195+
if (( ${#go_files[@]} == 0 )); then
196+
exit 0
197+
fi
198+
unformatted="$(gofmt -l "${go_files[@]}")"
199+
if [[ -n "${unformatted}" ]]; then
200+
echo "error: gofmt found unformatted files:"
201+
echo "${unformatted}"
202+
exit 1
203+
fi
204+
205+
release-docs-links:
206+
timeout-minutes: 10
207+
runs-on: ubuntu-latest
208+
steps:
209+
- name: Checkout
210+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
211+
212+
- name: Check markdown links
213+
uses: lycheeverse/lychee-action@82202e5e9c2f4ef1a55a3d02563e1cb6041e5332 # v2.4.1
214+
with:
215+
args: >-
216+
--glob
217+
--no-progress
218+
--verbose
219+
--exclude-mail
220+
--accept 429
221+
--max-retries 2
222+
--retry-wait-time 2
223+
README.md
224+
CONTRIBUTING.md
225+
AGENTS.md
226+
CHANGELOG.md
227+
SECURITY.md
228+
docs/**/*.md
229+
examples/**/*.md
230+
env:
231+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
232+
233+
release-platform-smoke:
234+
timeout-minutes: 30
235+
strategy:
236+
fail-fast: false
237+
matrix:
238+
os: [macos-latest, windows-latest]
239+
runs-on: ${{ matrix.os }}
240+
steps:
241+
- name: Checkout
242+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
243+
244+
- name: Set up Python
245+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
246+
with:
247+
python-version: ${{ env.PYTHON_VERSION }}
248+
249+
- name: Ensure jq is available (Windows)
250+
if: runner.os == 'Windows'
251+
shell: pwsh
252+
run: |
253+
if (Get-Command jq -ErrorAction SilentlyContinue) {
254+
jq --version
255+
exit 0
256+
}
257+
choco install jq --no-progress -y
258+
jq --version
259+
260+
- name: Run mock server integration tests (macOS)
261+
if: runner.os == 'macOS'
262+
shell: bash
263+
run: ./tools/tests/integration/run_mock_server_tests.sh
264+
265+
- name: Run mock server integration tests (Windows)
266+
if: runner.os == 'Windows'
267+
shell: pwsh
268+
run: ./tools/tests/integration/run_mock_server_tests.ps1

BUILD.bazel

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
# Root package exists to expose repository-level utility files to tests.
2-
exports_files(["bazelw"])
2+
exports_files([
3+
".bazelversion",
4+
"bazelw",
5+
])

CONTRIBUTING.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
- Python tooling tests:
3131
- `./bazelw test //tools/tests/python:python_tools_test`
3232
- Optional Python tooling dependencies (for local script execution):
33-
- `python3 -m pip install -r tools/requirements.txt`
33+
- `python3 -m pip install --require-hashes -r tools/requirements.txt`
3434
- Local lint prerequisites (match CI tooling):
3535
- `shellcheck` (shell lint lane)
3636
- `buildifier` (Starlark formatting lane)
@@ -40,7 +40,7 @@
4040
- Optional Python syntax smoke check when editing tooling:
4141
- `python3 -m py_compile tools/core/validate_payload_schema.py tools/core/schemas/sync_agentless_schema.py tools/tests/integration/mock_dd_server.py`
4242
- Integration harness:
43-
- Prerequisites: `jq` (Linux/macOS) and Git Bash available in PATH on Windows.
43+
- Prerequisites: `jq` (Linux/macOS). Windows harness is PowerShell-only.
4444
- Linux/macOS: `tools/tests/integration/run_mock_server_tests.sh`
4545
- Windows primary entrypoint: `tools/tests/integration/run_mock_server_tests.ps1`
4646
- Windows convenience wrapper: `tools/tests/integration/run_mock_server_tests.cmd`
@@ -71,6 +71,7 @@
7171
- scope policy: Linux-only by design today; non-Linux hermetic expansion is tracked separately to keep CI runtime bounded
7272
- Utility/lint lanes:
7373
- module version alignment check (`tools/dev/check_module_versions.py`)
74+
- `.bazelversion` parity check (`tools/dev/check_bazelversion_sync.py`)
7475
- shell scripts, PowerShell, Buildifier, gofmt, schema sync checks, fixture JSON checks, and Python tooling tests
7576
- Workflow dependency pinning:
7677
- Keep GitHub Actions pinned by commit SHA and preserve the `# vX.Y.Z` comment.

MODULE.bazel.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,11 @@ For a generic wrapper pattern, see [Other languages (without companion macro)](#
211211
- **Bazel 5.0+ minimum capability** - Earliest Bazel line with required `TEST_UNDECLARED_OUTPUTS_DIR` payload support
212212
- **Tracer/runtime with DD Test Optimization file-mode support** - Must honor `DD_TEST_OPTIMIZATION_MANIFEST_FILE` and `DD_TEST_OPTIMIZATION_PAYLOADS_IN_FILES`
213213
- **rules_go v0.51.0+** (for Go importpath inference) - This repository reads `GoInfo`/`GoArchive` providers when selecting per-module payloads
214-
- **DD_SITE format** - Accepts bare host, app/api-prefixed host, or full URL; normalized to `https://api.<site>`
214+
- **DD_SITE format** - Accepts bare host, app/api-prefixed host, or full URL; leading/trailing ASCII whitespace is trimmed, then normalized to `https://api.<site>`
215215
- **Uploader tooling (per platform)** - Required for `bazel run //:dd_upload_payloads`
216216
- **Linux**: `bash`, `curl`, `find`, `stat` (GNU), `awk`, and one of `md5sum` or `shasum`
217217
- **macOS**: `bash` (3.2+), `curl`, `find`, `stat` (BSD), `awk`, and one of `md5` or `shasum`
218-
- **Windows**: `powershell.exe` (Windows PowerShell 5.1+ or PowerShell 7+); the uploader uses .NET `HttpClient`
218+
- **Windows**: `powershell.exe` (Windows PowerShell 5.1+ or PowerShell 7+); the uploader uses .NET `HttpClient` and is intentionally PowerShell-only (no Git Bash dependency)
219219

220220
Optional tooling:
221221
- **jq** (Linux/macOS) - Used to enrich test payloads with `context.json`. If missing, uploads proceed without enrichment.
@@ -535,6 +535,7 @@ Fast checks before diving deep:
535535
- Full troubleshooting playbook: [`docs/Troubleshooting.md`](docs/Troubleshooting.md)
536536
- Configuration and fetch behavior reference: [`docs/Configuration_Reference.md`](docs/Configuration_Reference.md)
537537
- Uploader runtime reference: [`docs/Uploader_Reference.md`](docs/Uploader_Reference.md)
538+
- External-link provenance note: repository behavior is source-of-truth in this repo's code/tests; external docs are informative and may lag temporarily.
538539

539540
## Tips
540541

bazelw

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,37 @@ set -euo pipefail
77

88
now_ts="$(date +%s)"
99
ttl_seconds="${FETCH_SALT_TTL:-0}"
10+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11+
bazelversion_file="${script_dir}/.bazelversion"
12+
wanted_version=""
13+
if [[ -f "${bazelversion_file}" ]]; then
14+
wanted_version="$(tr -d '[:space:]' < "${bazelversion_file}")"
15+
fi
16+
if [[ -z "${wanted_version}" ]]; then
17+
echo "error: unable to read expected Bazel version from ${bazelversion_file}" >&2
18+
exit 127
19+
fi
20+
21+
extract_semver() {
22+
local raw="${1:-}"
23+
if [[ "${raw}" =~ ([0-9]+\.[0-9]+\.[0-9]+) ]]; then
24+
printf '%s' "${BASH_REMATCH[1]}"
25+
return 0
26+
fi
27+
return 1
28+
}
29+
30+
detect_system_bazel_version() {
31+
local raw=""
32+
local parsed=""
33+
raw="$(bazel --version 2>/dev/null || true)"
34+
parsed="$(extract_semver "${raw}" || true)"
35+
if [[ -z "${parsed}" ]]; then
36+
raw="$(bazel version 2>/dev/null | awk -F': ' '/Build label:/ { print $2; exit }')"
37+
parsed="$(extract_semver "${raw}" || true)"
38+
fi
39+
printf '%s' "${parsed}"
40+
}
1041

1142
if [[ "${ttl_seconds}" =~ ^[0-9]+$ ]] && [[ "${ttl_seconds}" -gt 0 ]]; then
1243
salt=$(( now_ts / ttl_seconds ))
@@ -16,8 +47,24 @@ fi
1647

1748
if command -v bazelisk >/dev/null 2>&1; then
1849
bazel_cmd="bazelisk"
50+
elif command -v bazel >/dev/null 2>&1; then
51+
system_bazel_version="$(detect_system_bazel_version)"
52+
if [[ "${BAZELW_ALLOW_SYSTEM_BAZEL:-0}" == "1" ]]; then
53+
echo "warning: bazelisk not found; using system bazel due to BAZELW_ALLOW_SYSTEM_BAZEL=1" >&2
54+
bazel_cmd="bazel"
55+
elif [[ -z "${system_bazel_version}" ]]; then
56+
echo "error: bazelisk is required to enforce .bazelversion (unable to detect system bazel version)." >&2
57+
exit 127
58+
elif [[ "$system_bazel_version" == "$wanted_version" ]]; then
59+
echo "warning: bazelisk not found; using system bazel version $system_bazel_version (matches .bazelversion)" >&2
60+
bazel_cmd="bazel"
61+
else
62+
echo "error: bazelisk is required to enforce .bazelversion (wanted $wanted_version, found system bazel $system_bazel_version)." >&2
63+
exit 127
64+
fi
1965
else
20-
bazel_cmd="bazel"
66+
echo "error: bazelisk is required to enforce .bazelversion (set BAZELW_ALLOW_SYSTEM_BAZEL=1 to override)." >&2
67+
exit 127
2168
fi
2269

2370
sanitize_repository_url() {

0 commit comments

Comments
 (0)