Repository navigation
ci: exercise the locked install path #7238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3ab32f5
a36eb8f
b178e26
7d094b4
07015ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,10 +2,24 @@ name: validate-lockfiles | |
|
|
||
| on: | ||
| pull_request: | ||
| types: | ||
| - opened | ||
| - synchronize | ||
| - reopened | ||
| - labeled | ||
| # Wide enough for whichever of the two jobs below could be affected. They no | ||
| # longer share one gate: the cheap lint runs on anything reaching this | ||
| # workflow, and the two cold container builds gate themselves on a | ||
| # changed-files job scoped to what the `base` target actually consumes. | ||
| # Markdown is excluded outright — 19 READMEs live under ansible/roles/**, | ||
| # and a docs-only PR must start neither job. | ||
| paths: | ||
| - ansible/vars/locked-versions-*.yaml | ||
| - ansible/** | ||
| - ansible-galaxy-requirements.yaml | ||
| - docker/*.Dockerfile | ||
| - docker/docker-bake.hcl | ||
| - .github/workflows/validate-lockfiles.yaml | ||
| - "!**/*.md" | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
|
|
@@ -28,3 +42,84 @@ jobs: | |
|
|
||
| - name: Validate lockfiles (format + digest/lockfile coverage) | ||
| run: ./ansible/scripts/validate_lockfiles.sh | ||
|
|
||
| # What a locked `base` bake resolves against: the roles install_rmw runs, the | ||
| # lockfile it reads, the collection those roles are resolved from, and the two | ||
| # docker files the bake itself consumes. Deliberately narrower than the | ||
| # workflow trigger above — ansible/scripts/** and the other four playbooks | ||
| # reach the lint but no bake. | ||
| changed-files: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| should-run: ${{ steps.check.outputs.any_modified }} | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - id: check | ||
| uses: step-security/changed-files@v47 | ||
| with: | ||
| files: | | ||
| ansible/roles/** | ||
| ansible/vars/** | ||
| ansible/playbooks/install_rmw.yaml | ||
| ansible-galaxy-requirements.yaml | ||
| docker/base.Dockerfile | ||
| docker/docker-bake.hcl | ||
| .github/workflows/validate-lockfiles.yaml | ||
| files_ignore: | | ||
| ansible/roles/artifacts/** | ||
| **/*.md | ||
|
|
||
| # The locked base bakes below are two cold, uncached container builds. Put | ||
| # them behind the same opt-in label the repo already uses for its other | ||
| # expensive lanes, wired to run-condition exactly as health-check-ansible.yaml, | ||
| # health-check-ansible-artifacts.yaml and health-check-pr.yaml wire theirs. | ||
| # Without run-condition this call site reports red — not skipped — on any PR | ||
| # that reaches the workflow without touching a bake input, and all four sites | ||
| # publish the same required `require-label / require-label` context. | ||
| require-label: | ||
| needs: changed-files | ||
| if: ${{ always() }} | ||
| uses: autowarefoundation/autoware-github-actions/.github/workflows/require-label.yaml@v1 | ||
| with: | ||
| label: run:health-check | ||
|
Comment on lines
+82
to
+87
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This call site has no The reusable workflow guards its inner job with All four emit the same context, I am not certain that red blocks the merge, because this PR carries four check runs under that one name and GitHub resolves the context from the most recent of them. Either way, a red check on a workflow-only PR reads as a regression. If the job moves into
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. On resolving it by moving the job into |
||
| run-condition: ${{ needs.changed-files.outputs.should-run == 'true' }} | ||
|
|
||
| build-locked-base: | ||
| needs: require-label | ||
| if: needs.require-label.outputs.result == 'true' | ||
| runs-on: ubuntu-24.04 | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| rosdistro: [humble, jazzy] | ||
|
youtalk marked this conversation as resolved.
Resolved
|
||
| steps: | ||
| - name: Check out repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v4 | ||
|
|
||
| - name: Build the locked base image | ||
| run: USE_LOCKFILE=true ROS_DISTRO=${{ matrix.rosdistro }} docker buildx bake -f docker/docker-bake.hcl base | ||
|
|
||
| # The matrix above emits one context per distro, none of which is a stable | ||
| # name a branch ruleset can require. Aggregate them into one, the same way | ||
| # health-check-ansible.yaml aggregates install-dev-env, so this lane can be | ||
| # promoted to a required check without the name changing again when a distro | ||
| # is added or dropped. | ||
| build-locked-base-required: | ||
| needs: build-locked-base | ||
| if: ${{ !cancelled() }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Verify build-locked-base outcome | ||
| run: | | ||
| result="${{ needs.build-locked-base.result }}" | ||
| echo "build-locked-base: $result" | ||
| case "$result" in | ||
| success|skipped) exit 0 ;; | ||
| *) exit 1 ;; | ||
| esac | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # Configure the dated Ubuntu archive snapshot apt source (locked mode). | ||
| # | ||
| # An exact-version pin in /etc/apt/preferences.d/autoware-lock only binds a | ||
| # version apt can actually reach. Ubuntu drops a superseded build from | ||
| # <suite>-updates and <suite>-security as soon as it publishes the replacement, | ||
| # so a pin taken at lockfile-generation time stops matching anything the moment | ||
| # a security update lands. apt then silently installs the current candidate and | ||
| # tasks/verify.yaml fails the play on the drift. This decayed on its own 17 days | ||
| # after the lockfiles were last regenerated (wget, both distros), with no change | ||
| # to the repository. | ||
| # | ||
| # snapshot.ubuntu.com republishes the archive as it stood at a given timestamp, | ||
| # so pointing at the lockfile's own date makes every pinned build downloadable | ||
| # again. It is the Ubuntu-archive counterpart to the dated snapshots.ros.org | ||
| # source the ros2 role configures (roles/ros2/tasks/snapshot_source.yaml). | ||
| # | ||
| # Added ALONGSIDE the distribution's own sources rather than replacing them: | ||
| # - The pins are the contract for Ubuntu-archive packages, and at priority | ||
| # 1001 they select the locked build wherever it is served. This source only | ||
| # has to keep that build reachable; it does not need to win by itself. | ||
| # - install_dev_env runs on developer machines, and rewriting a user's | ||
| # /etc/apt/sources.list is not this role's to do. | ||
| # - Packages outside apt_pins keep resolving exactly as they do today, so the | ||
| # change has no effect on anything but a pin that would otherwise be | ||
| # unreachable. A newly-introduced Ubuntu-archive package that nobody pinned | ||
| # is caught separately, by files/check_pin_completeness.py in verify.yaml. | ||
| # | ||
| # Callers do not import this file directly; tasks/main.yaml runs it in locked mode. | ||
| - name: Assert lockfile provides an Ubuntu snapshot date | ||
| ansible.builtin.assert: | ||
| that: | ||
| - locked_packages.ubuntu_snapshot_date is defined | ||
| - locked_packages.ubuntu_snapshot_date | string | length > 0 | ||
| fail_msg: >- | ||
| Locked mode requires 'ubuntu_snapshot_date' in {{ lockfile_path }} | ||
| (snapshot.ubuntu.com timestamp, e.g. 20260805T000000Z). | ||
| quiet: true | ||
|
|
||
| # snapshot.ubuntu.com is https-only (plain http 301-redirects to it), and the | ||
| # minimal Ubuntu images CI runs in ship no CA bundle. Install it from whatever | ||
| # sources are configured now, before apt has to speak TLS. Not pinned: it is a | ||
| # bootstrap prerequisite of this source, in the same spirit as python3-apt in | ||
| # main.yaml, and it is installed before the pin-completeness baseline is taken. | ||
| - name: Install ca-certificates so apt can reach the snapshot over https | ||
| become: true | ||
| ansible.builtin.apt: | ||
| name: ca-certificates | ||
| state: present | ||
| update_cache: true | ||
|
|
||
| - name: Write dated Ubuntu snapshot apt source | ||
| become: true | ||
| ansible.builtin.template: | ||
| src: ubuntu-snapshot.sources.j2 | ||
| dest: /etc/apt/sources.list.d/ubuntu-snapshot.sources | ||
| owner: root | ||
| group: root | ||
| mode: "0644" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| {# Rendered to /etc/apt/sources.list.d/ubuntu-snapshot.sources in locked mode. #} | ||
| {# Added alongside the distribution's own sources, not in place of them: the #} | ||
| {# exact-version pins in /etc/apt/preferences.d/autoware-lock (priority 1001) #} | ||
| {# decide which candidate wins, and this source only has to make the pinned #} | ||
| {# build downloadable again once the live pockets drop it. See #} | ||
| {# tasks/ubuntu_snapshot_source.yaml for why. #} | ||
| {# Signed by the stock Ubuntu archive key: snapshot.ubuntu.com republishes the #} | ||
| {# original Release files, so no extra keyring is needed. #} | ||
| Types: deb | ||
| URIs: https://snapshot.ubuntu.com/ubuntu/{{ locked_packages.ubuntu_snapshot_date }} | ||
| Suites: {{ ansible_distribution_release }} {{ ansible_distribution_release }}-updates {{ ansible_distribution_release }}-backports {{ ansible_distribution_release }}-security | ||
| Components: main restricted universe multiverse | ||
| Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,20 @@ if [[ -z ${ROS_SNAPSHOT_DATE:-} ]]; then | |
| echo "Error: ROS_SNAPSHOT_DATE is not set (e.g. 2026-04-13)." >&2 | ||
| exit 1 | ||
| fi | ||
| # The Ubuntu archive counterpart of ROS_SNAPSHOT_DATE. Take it at the same time | ||
| # as the apt versions recorded below: snapshot.ubuntu.com is what keeps those | ||
| # builds downloadable once the live pockets supersede them, so a timestamp from | ||
| # before this run would freeze the archive at versions that are not the ones | ||
| # pinned here. | ||
| if [[ -z ${UBUNTU_SNAPSHOT_DATE:-} ]]; then | ||
| echo "Error: UBUNTU_SNAPSHOT_DATE is not set (snapshot.ubuntu.com timestamp, e.g. 20260805T000000Z)." >&2 | ||
| echo "Hint: date -u +%Y%m%dT000000Z" >&2 | ||
| exit 1 | ||
|
Comment on lines
+20
to
+23
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Supply the new required timestamp in the regeneration workflow This guard makes Please supply I reproduced exit status The failure occurs before architecture detection. In a disposable package fixture, supplying the variable lets the copied workflow shell step finish. The full regeneration workflow did not run. |
||
| fi | ||
| if [[ ! $UBUNTU_SNAPSHOT_DATE =~ ^[0-9]{8}T[0-9]{6}Z$ ]]; then | ||
| echo "Error: UBUNTU_SNAPSHOT_DATE must look like 20260805T000000Z, got '${UBUNTU_SNAPSHOT_DATE}'." >&2 | ||
| exit 1 | ||
| fi | ||
| ARCH=$(dpkg --print-architecture) | ||
| OUTPUT_FILE="${ANSIBLE_DIR}/vars/locked-versions-${ROS_DISTRO}-${ARCH}.yaml" | ||
|
|
||
|
|
@@ -117,6 +131,12 @@ else: | |
| # | ||
| # ros_snapshot_date freezes every ROS package snapshots.ros.org serves on that date. | ||
| ros_snapshot_date: "${ROS_SNAPSHOT_DATE}" | ||
| # | ||
| # ubuntu_snapshot_date freezes what the Ubuntu archive can still serve: snapshot.ubuntu.com | ||
| # republishes the pockets as they stood at that timestamp, so every apt_pins build below | ||
| # stays downloadable after the live pockets supersede it. Take it at the same time as the | ||
| # versions below, or a pin here will resolve to nothing. | ||
| ubuntu_snapshot_date: ${UBUNTU_SNAPSHOT_DATE} | ||
| apt_pins: | ||
| HEADER | ||
| for pkg in "${apt_packages[@]}"; do | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.