Skip to content

The rows job masks what identifies its machine in all it publishes - #1281

Draft
Japabu wants to merge 4 commits into
mainfrom
ci-log-masks-machine
Draft

Japabu wants to merge 4 commits into
mainfrom
ci-log-masks-machine

Conversation

@Japabu

@Japabu Japabu commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

guest-rows.yml runs on our own machine, and its log, step summary and serial artifact are public. The rows job printed the host CPU's brand string in each instrument line and in the summary. A KVM guest's CPU is its host's, so every guest's kernel lines carry the host CPU's signature and microcode revision (microcode: cpuN … signature … found … running …, fpu: cpuN cpuid.1.eax=…), osbench's cond cpu_model= carries the brand, and #1277's words line would add signature= and microcode=. A red row echoes those lines into the log and keeps them in the uploaded serial logs.

What changes

  • The instrument line names no CPU. It keeps the QEMU version, the firmware, the accelerator and the core count.
  • The rows job reads its machine before it runs anything: each CPU's brand string, CPUID.01H:EAX and microcode revision from /proc/cpuinfo, and the kernel's host name. The signature is rebuilt from the display family, model and stepping as Intel SDM Vol. 2A's CPUID and AMD's APM Vol. 3 Fn0000_0001_EAX lay them out. A machine the job cannot read these from runs no suite, because what the job cannot read it cannot mask. The step's verdict names what is missing and none of what was read.
  • The relay masks each line whole as it ends (heard). The log, the verdicts and the step summary read off it are masked. An unfinished line is said when it ends or when the command does, and a hung step's refusal still names it, masked.
  • A red run's kept serial logs are masked in place before the workflow uploads them. If one cannot be masked, they are all removed instead of being uploaded.
  • guest-rows.yml's header states the host's half: the runner writes the runner's and host's names before the job's first step, so neither name may identify anybody.
  • issues/the-guest-runners-public-logs-name-its-machine.md records what remains and the owner's rulings (below).

Decisions

  • Values read from the machine, not shapes shared with build/sourcegate.rs. The brief preferred one definition shared with sourcegate. Sourcegate's tracked-tree gate cannot refuse a signature or microcode shape, because the tree names CPUs by signature on purpose: the benches' microcode selection, Intel's affected-processor tables in the mitigation decision, readback fixtures and issue records. None of sourcegate's existing shapes matches what identifies this runner (MAC, public or shared IPv4, global or link-local IPv6, serial number, macOS's default personal host name). Because the values come from the machine itself, each one is masked however a printer spells it: hex with 0x or without, zero-padded or upper-case, Debug's decimal for the signature, and words separated by spaces or by osbench's _ for the brand and the host name.
  • A microcode revision is masked only after 0x. In any other spelling a revision is just a small number, such as 190 or the word be.
  • Only the rows job masks. The nightly guest job runs on GitHub's machines, which identify nobody of ours. A hypervisor's placeholder revision there would mask every matching token in that log. Host jobs and the nightly guest job pass Identity::NONE, so their output is unchanged except that it now passes through a line at a time.

The owner's rulings (2026-11-12)

Recorded in issues/the-guest-runners-public-logs-name-its-machine.md, which the orchestrator holds.

  1. The runner names the host. In "Set up job", before any step, the runner writes Machine name:, which no job code can mask. The owner is renaming the host to a neutral name, so this PR adds no code for it. Until the rename, every guest-rows run publishes the name, this PR's evidence run included.
  2. Earlier runs. After the rename, the orchestrator deletes the logs and serial artifacts of every affected guest-rows run, and keeps the runs themselves. Guest runs continue meanwhile.
  3. Measured values do not identify the machine. A KVM guest's TSC rate, XSAVE layout and feature words are its host's. They stay unmasked.

Checks

Status: draft. The guest run is still queued. This section is updated when it finishes.

Head 7fbf8ee2a, on main 302fb3698. Since 9963b222c, where the host check and the controls ran, the head changes only the issue record and a comment in guest-rows.yml. cargo test --lib -- ci::tests sourcegate::tests was re-run on that content and exits 0 (35 passed), and sourcegate::tests was re-run again on the final record (9 passed).

  • Masking tests (cargo test --lib -- ci::tests, macOS host): exit 0, 26 passed and 6 ignored, as before. The new tests are a_signature_is_its_family_model_and_stepping_as_the_vendors_lay_them_out, a_machine_is_read_whole_or_refused, each_value_is_masked_however_it_is_spelled_and_what_resembles_it_is_not, the_relay_masks_a_value_it_reads_in_pieces and every_kept_serial_log_is_masked_in_place. Each value is tested in the spellings a log gives it: the kernel's microcode: and fpu: lines, Each CPU's bring-up writes SPEC_CTRL and clears the MCU_OPT_CTRL opt-outs its decision names #1277's words line, Debug's decimal, osbench's cond cpu_model=, /proc/cpuinfo and the runner's own line. Each also has negatives that only resemble it: a neighbouring value, a longer token, 0x86_0f01, the revision in decimal and bare hex, a partial or altered brand, and somebody-pcs and somebody's pc. The signature oracle is the two benches' signatures as their own boots logged them (tests/checks/readbacks).
  • Mutation controls: each was applied to the head as a patch, built, and its ci::tests run, then reverted (git diff empty afterwards). Every one exits 101 and reds the test that holds it:
    • the relay says lines unmasked: the_relay_masks_a_value_it_reads_in_pieces;
    • no microcode value is read: four tests;
    • kept serial logs are written back unmasked: every_kept_serial_log_is_masked_in_place;
    • the 0x-only rule for a revision is dropped: each_value_is_masked_….
  • cargo run -- --ci host on 9963b222c (macOS host): exit 1, with 122 of 123 steps green. The one red step is the build system's cargo test --lib, in which two tests fail: llvm::tests::the_caller_s_environment_reaches_neither_the_build_nor_the_key and the child it runs, keyed_and_built. That failure is the known macOS one in issues/the-llvm-environment-test-breaks-git-on-macos.md (xcode-select cannot find git under SDKROOT=/no/such.sdk), and this PR touches nothing in build/llvm.rs. In the same run the new tests, all of ci::tests and sourcegate::tests::no_tracked_file_identifies_a_machine_or_its_network pass.
  • Guest run: run 43164907090 is queued. It runs osbench_capability_groups_exit_0 on the guest runner from ci-log-masks-machine-demo, which is this head's parent plus one evidence-only commit that never lands. That commit makes the row print its whole console and red, so the log carries a KVM guest's kernel and osbench lines and the run keeps serial logs. The commit since that parent changes only the identity step's refusal text. The negative control is run 43143902443, at a base without this change, whose log carries those lines unmasked; it is cited, not republished.

🤖 Generated with Claude Code

Japabu and others added 4 commits November 12, 2026 07:55
The guest-rows job runs on our own machine and its log, step summary and
serial artifact are public. Its instrument line printed the host CPU's brand
string, and every KVM guest's kernel lines carry the host CPU's signature and
microcode revision (`microcode:`, `fpu: cpuid.1.eax=`), as osbench's
`cond cpu_model=` carries the brand.

The rows job now reads what identifies the machine from the machine itself,
`/proc/cpuinfo` and the kernel's host name, before it runs anything, and
refuses to run a suite where it cannot. The relay that passes the suite's
output through masks each line whole as it ends, so the log, the verdicts
and the summary read off it are masked, and a red run's kept serial logs are
masked in place before the workflow uploads them. The instrument line no
longer names the CPU.

The values are the machine's own rather than shapes: the tree names the
benches' CPUs by signature on purpose, so no shape can refuse a signature,
and a value read from the machine is masked in whatever spelling a guest's
printer chooses. A microcode revision is masked only after `0x`, since its
other spellings are any small number.

The runner itself names the host before the first step, and earlier runs
carry the values: issues/the-guest-runners-public-logs-name-its-machine.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The identity step's verdict is published, so a field that does not parse,
or a model or host name with no word to mask, is refused by its name alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every run carries the runner's host name, but only one that reached its
instrument step carries the brand string. One serial artifact was sampled,
and the record now says which. The workflow's comment names the job's log
as the public one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The owner renames the host, and after the rename the orchestrator deletes
the logs and serial artifacts of every earlier run, keeping the runs. Guest
runs continue meanwhile. The owner ruled that the measured values a KVM guest
reads of its host (TSC rate, XSAVE layout, feature words) do not identify the
machine, so they stay unmasked. The record is now held work, not a question.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant