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
2 changes: 1 addition & 1 deletion .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Before starting, verify:

4. **The `[Unreleased]` section of `CHANGELOG.md` has entries**. If it is empty, warn the user — a release with no changelog entries is unusual.

5. **Review pinned Docker dependencies**: Check that base image digests and apt package versions are current. If Dependabot PRs for Docker digests have been merged since the last release, flag this so the user can verify pinned apt versions still match.
5. **Review pinned Docker dependencies**: Check for open Dependabot base-image digest PRs and open `apt-pin-check` PRs, and flag them so the user can merge them before tagging. No manual verification of apt versions is needed: the production stages run `apt-get upgrade` before the pinned installs (a stale pin fails the build), and the `scan-images` CI job builds and scans every production image on each push to `main`.

## Documentation Review and Update

Expand Down
56 changes: 1 addition & 55 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -433,64 +433,14 @@ jobs:
# never uploaded again. See discover-base-images.ps1.
category: trivy-image-${{ matrix.image_name }}

retire-base-image-scan-categories:
# MIGRATION STEP: remove this job once the three configurations below have been
# deleted from Security > Code scanning > Tool status (Trivy).
#
# Code scanning remembers every category a workflow has ever uploaded for the
# default branch as a "configuration", and the Trivy merge check compares a PR
# against all of them. When scan-images replaced the base-image scan, the three
# trivy-base-image-* categories stopped being uploaded, the check reported
# "3 configurations present on main were not found", and the ruleset's
# code-scanning requirement blocked the PR (#1637) with every job green. An
# analysis with no results, uploaded under each retired category, satisfies the
# comparison, and once it lands on main it closes every alert those categories
# still hold as fixed; the base image findings they carried are now reported,
# where they still apply, by the built-image scan. Deleting the configurations
# is API/UI-only and cannot be done from a workflow, which is why this is a
# step to remove by hand rather than one that retires itself.
runs-on: ${{ github.event_name == 'push' && 'self-hosted' || 'ubuntu-latest' }}
permissions:
contents: read
security-events: write # required to upload SARIF to code scanning

strategy:
fail-fast: false
matrix:
base_image: [aspnet, runtime, sdk]

steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Write an empty Trivy analysis
run: |
cat > retired-category.sarif <<'EOF'
{
"version": "2.1.0",
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"runs": [
{
"tool": { "driver": { "name": "Trivy", "informationUri": "https://github.com/aquasecurity/trivy" } },
"results": []
}
]
}
EOF

- name: Upload the empty analysis under the retired category
uses: github/codeql-action/upload-sarif@6f5948dfacef28e207b48d0905cf90c03365536d # v3.37.9
with:
sarif_file: retired-category.sarif
category: trivy-base-image-mcr-microsoft-com-dotnet-${{ matrix.base_image }}

scan-base-images-summary:
# Stable-name gate for the dynamic scan-images matrix, providing the single
# check name the branch protection ruleset requires. The name predates the
# move from scanning base images to scanning the built JIM images and is
# kept because the ruleset names it; renaming it here without changing the
# ruleset would leave every PR waiting on a check that never reports.
if: always()
needs: [discover-base-images, scan-images, retire-base-image-scan-categories]
needs: [discover-base-images, scan-images]
runs-on: ${{ github.event_name == 'push' && 'self-hosted' || 'ubuntu-latest' }}
steps:
- name: Check matrix results
Expand All @@ -503,8 +453,4 @@ jobs:
echo "One or more scan-images matrix legs failed"
exit 1
fi
if [ "${{ needs.retire-base-image-scan-categories.result }}" != "success" ]; then
echo "One or more retired-category uploads failed"
exit 1
fi
echo "All image scans passed"
18 changes: 17 additions & 1 deletion engineering/DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,23 @@ When adding a new production Dockerfile:

Vulnerability scanning (`scan-images`) builds every production JIM image on every push and PR and scans the result: the built image is what customers run, and it alone carries the apt pins and the build-time upgrade. Findings are surfaced in the GitHub Security tab via SARIF upload (one category per JIM image) in addition to the Actions log, so they are visible to reviewers and auditable after the fact.

**Retiring a code scanning category.** Code scanning remembers every SARIF category a workflow has uploaded for `main` as a "configuration", and the per-tool merge check compares each PR against all of them: a PR whose workflow stops uploading a category is reported as "configurations present on main were not found" and the ruleset's code-scanning requirement blocks the merge with every job green (seen on #1637 when the base-image scan became the built-image scan). Two steps retire one cleanly: keep uploading an empty analysis under the old category until the change has landed (the `retire-base-image-scan-categories` job does this; on `main` it also closes the category's remaining alerts as fixed), then delete the configuration from *Security > Code scanning > Tool status* and remove the job. Deletion is UI/API-only, so it cannot be folded into the workflow.
**Retiring a code scanning category.** Code scanning remembers every SARIF category a workflow has uploaded for `main` as a "configuration", and the per-tool merge check compares each PR against all of them: a PR whose workflow stops uploading a category is reported as "configurations present on main were not found" and the ruleset's code-scanning requirement blocks the merge with every job green (seen on #1637 when the base-image scan became the built-image scan). Two steps retire one cleanly: keep uploading an empty analysis under the old category until the change has landed (a small matrix job writing a SARIF file with no results and passing it to `upload-sarif` with the old `category`; on `main` that also closes the category's remaining alerts as fixed), then delete every analysis in the category and remove the job. Deletion is API-only (the Tool status page lists configurations but cannot delete them), and the API deletes one *set* at a time (one set per category per git ref), so it has to be driven to exhaustion:

```bash
repo=repos/TetronIO/JIM
while :; do
urls=$(gh api "$repo/code-scanning/analyses?tool_name=Trivy&per_page=100" --paginate \
--jq '.[] | select((.category|startswith("<old-category-prefix>")) and .deletable==true) | .url')
[ -z "$urls" ] && break
for url in $urls; do
while [ -n "$url" ]; do
url=$(gh api -X DELETE "$url?confirm_delete" --jq '.next_analysis_url // empty' 2>/dev/null) || break
done
done
done
```

Budget for it: retiring the three base-image categories on #1637 meant about 8,000 deletions against the 5,000-per-hour API limit, so run it detached (`nohup`) with a retry on rate-limit refusals, and expect it to take a couple of hours.

**Why this matters**: `System.DirectoryServices.Protocols` (the .NET LDAP client) P/Invokes into the native `libldap` shared library at runtime. An incompatible libldap version could cause silent behavioural differences or crashes during LDAP/AD operations.

Expand Down
6 changes: 2 additions & 4 deletions engineering/RELEASE_PROCESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,9 @@ git push origin main --tags

### Steps

1. **Review pinned Docker dependencies**: Check that base image digests and apt package versions are up to date. If Dependabot PRs for Docker digests have been merged since the last release, verify the pinned apt versions still match. If not, update them:
1. **Review pinned Docker dependencies**: merge any open Dependabot base-image digest PR and any open `apt-pin-check` PR before tagging, so the release ships the newest base image and current apt pins. Nothing needs checking by hand beyond that: every production stage runs `apt-get upgrade` before its pinned installs, so a stale pin fails the image build rather than shipping, and the `scan-images` CI job builds and scans every production image on each push to `main`, failing on any fixable HIGH/CRITICAL CVE. Confirm the latest `main` run is green. To inspect the archive's current versions for a pin by hand (the `apt-pin-check` workflow does this daily):
```bash
# Check available versions in the current base image
docker run --rm mcr.microsoft.com/dotnet/aspnet:10.0@sha256:<current-digest> bash -c \
"apt-get update -qq && apt-cache policy libldap-common libldap-2.5-0 cifs-utils"
pwsh -File ./.github/scripts/check-apt-pins.ps1
```

2. **Update the changelog**: Move items from `[Unreleased]` to a new version section in `CHANGELOG.md`
Expand Down
Loading