Skip to content
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
c11bd6b
fix: scale the default relaxation window to the system's own relaxati…
claude Aug 16, 2026
16fba4d
test: share diagnose() runs across the scaling assertions
claude Aug 16, 2026
86442a0
docs(citation): record the relaxation-window correction as pending fo…
claude Aug 16, 2026
f132bea
fix: disclose unsampled fast modes, store the time grid (PR #115 review)
claude Aug 16, 2026
72b7da3
fix: count the unsampled lead-in in the fast-mode resolution check
claude Aug 16, 2026
4c45527
fix(relaxation): repair the two-scale window instead of disclosing it…
Aug 29, 2026
48b5253
test: pin the repair and its limits (CAR(1) model + two-scale window)
Aug 29, 2026
5455642
docs: describe the two-scale window and the CAR(1) residual model
Aug 29, 2026
3d9b6b8
docs: replace the inherited whitening figures with own measurements
Aug 29, 2026
9288ee8
fix(relaxation): stop leaking Any out of the two-scale grid builder
Aug 29, 2026
bffb15a
Merge remote-tracking branch 'origin/main' into fix/115-zweiskalen-car1
marcohost33-maker Aug 29, 2026
4d9a99f
fix(certificate,fits): four external-review findings on PR #127
marcohost33-maker Aug 29, 2026
3abb353
docs: record the four PR #127 review findings and the new residual_mo…
marcohost33-maker Aug 29, 2026
21c99ee
Merge remote-tracking branch 'origin/main' into pr127-work
marcohost33-maker Sep 2, 2026
71e5f39
fix(#127): D3, D4 and the oscillation flag survived the withholding o…
marcohost33-maker Sep 2, 2026
c07141b
fix(#127): four values withheld at one layer, consumed as measurement…
marcohost33-maker Sep 3, 2026
a84a009
fix(#127 round-19): scale-relative Prony gate, withheld window, gauge…
marcohost33-maker Sep 3, 2026
3ce21a8
test(#127 round-19): repair two blind spots the mutation run found
marcohost33-maker Sep 3, 2026
bd06e65
fix(#127 round-20): the gauge shift overflowed and the gate then fail…
marcohost33-maker Sep 3, 2026
18cef39
fix(#127 round-20): an underflowed resolution ratio crashed instead o…
marcohost33-maker Sep 3, 2026
ce9ac67
perf(#127 round-20): the exact CAR(1) ESS no longer builds two n x n …
marcohost33-maker Sep 3, 2026
d68800a
docs(#127): the AICc likelihood mismatch bites only where the theta s…
marcohost33-maker Sep 4, 2026
df0a3e5
docs(#127): the Hermiticity verdict is not gauge invariant, and that …
marcohost33-maker Sep 4, 2026
216324c
fix(#127 CI): the pure-gauge fixture asked the BLAS for its defect
marcohost33-maker Sep 4, 2026
e0a6479
fix(#127 round-20): the bootstrap drew innovations the fitter had not…
marcohost33-maker Sep 4, 2026
10589f0
fix(#127): measure the Hermiticity defect against the generator, not …
marcohost33-maker Sep 11, 2026
ddcaceb
docs(#127): changelog for the generator-relative tolerance; mark the …
marcohost33-maker Sep 11, 2026
f925705
Merge origin/main (38f8652) into PR #127: one finding repaired twice,…
marcohost33-maker Sep 11, 2026
e95ca8b
fix(#127 review round 2): read the generator scale in the canonical L…
marcohost33-maker Sep 11, 2026
5bc1c44
docs(#127 review round 2): CHANGELOG precision and CITATION.cff entry…
marcohost33-maker Sep 11, 2026
1c65460
test(#127 review round 3): pin the rate in the Lindblad-gauge compens…
marcohost33-maker Sep 11, 2026
b4ade40
fix(#127 CI): widen the annotation of the dissipator accumulator for …
marcohost33-maker Sep 11, 2026
8ab22ad
Merge origin/main (4f9592b, #139) into PR #127: keep both pending CIT…
marcohost33-maker Sep 11, 2026
eafc1b7
chore: stage guarded E3 contract migration
marcohost33-maker Sep 12, 2026
63adafa
chore: run one-shot E3 contract migration
marcohost33-maker Sep 12, 2026
57ed1c0
chore: replace failed E3 one-shot workflow
marcohost33-maker Sep 12, 2026
1373c47
chore: rerun guarded E3 migration with duplicate-signature cleanup
marcohost33-maker Sep 12, 2026
52f3be4
fix(lindblad): bind H Hermiticity to coherent scale
github-actions[bot] Sep 12, 2026
100e1c0
chore: remove stale E3 open-question comments
marcohost33-maker Sep 12, 2026
e556c96
chore(pr127): remove completed one-shot cleanup workflow
marcohost33-maker Sep 12, 2026
bb397ff
fix(#127 review round 21): close four review findings and align the r…
claude Sep 13, 2026
141badf
fix(#154 review): do not forward an unresolved spectrum to the relaxa…
claude Sep 13, 2026
e7e17d2
fix(#154 review, round 2): derive the certificate verdict for caller-…
claude Sep 13, 2026
4dd8c61
fix(#154 review, round 3): refuse spectrum_resolved=True without eige…
claude Sep 13, 2026
2c5fcc0
Merge pull request #154 from marcohost33-maker/claude/next-steps-zmsugb
marcohost33-maker Sep 14, 2026
e7e7c65
fix(#127): kein doppelter Modul-Import im Runde-21-Test (CodeQL 34)
claude Sep 14, 2026
ae9f432
Merge pull request #155 from marcohost33-maker/claude/next-steps-zmsugb
marcohost33-maker Sep 14, 2026
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
68 changes: 60 additions & 8 deletions .github/scripts/check_workflow_hardening.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@
ROOT = Path(__file__).resolve().parents[2]
WORKFLOWS = ROOT / ".github" / "workflows"
FULL_SHA_RE = re.compile(r"^[0-9a-f]{40}$", re.IGNORECASE)
USES_RE = re.compile(r"^\s*uses:\s*([^\s#]+)")
# Container images pin by digest, which is a different shape from a git SHA.
DIGEST_RE = re.compile(r"^sha256:[0-9a-f]{64}$", re.IGNORECASE)
# ``- uses:`` (list form) is the commonest way to write a step, and the
# previous pattern did not match it: 7 of 27 refs in this tree were
# invisible to the gate, including every ``actions/checkout``. They were
# pinned by discipline, not by this check. Proven as a pair -- the same
# unpinned ref passes in list form and is caught in block form.
USES_RE = re.compile(r"^\s*(?:-\s*)?uses:\s*([^\s#]+)")


def _iter_workflow_files() -> list[Path]:
Expand All @@ -28,11 +35,23 @@ def _iter_workflow_files() -> list[Path]:


def _is_third_party_uses(ref: str) -> bool:
return not (
ref.startswith("./")
or ref.startswith("docker://")
or ref.startswith("github.com/")
)
"""Which refs must carry a pin.

``docker://`` was exempt outright, so ``docker://org/img:latest`` -- a
mutable tag from a third party -- passed the gate. It is exempt only
when it carries an immutable digest. The former ``github.com/``
exemption was dead code: ``uses:`` does not accept that prefix, and a
GitHub owner name cannot contain a dot, so no such org can exist. It
also tripped a CodeQL incomplete-substring alert, which is how it was
found.
"""
if ref.startswith("./"):
return False
if ref.startswith("docker://"):
# Third party either way. Whether the pin is adequate is decided
# in _check_uses_pin, which alone sees the ref undivided.
return True
return True


def _check_uses_pin(path: Path, line_number: int, line: str, errors: list[str]) -> None:
Expand All @@ -49,24 +68,57 @@ def _check_uses_pin(path: Path, line_number: int, line: str, errors: list[str])
action, version = ref.rsplit("@", 1)
if not _is_third_party_uses(action):
return
if action.startswith("docker://"):
# A container pins by image digest, not by a git SHA. Requiring the
# git form here would reject the very thing the rule asks for.
if not DIGEST_RE.fullmatch(version):
errors.append(
f"{path}:{line_number}: container must be pinned to an "
f"immutable @sha256: digest, got {ref}"
)
return
if not FULL_SHA_RE.fullmatch(version):
errors.append(
f"{path}:{line_number}: action must be pinned to a full 40-char SHA, got {ref}"
)


def _check_privileged_trigger(path: Path, text: str, errors: list[str]) -> None:
if "pull_request_target" in text and "ALLOW_PULL_REQUEST_TARGET:" not in text:
"""The rationale must be a real key, not the words in a comment.

``"ALLOW_PULL_REQUEST_TARGET:" in text`` was satisfied by any
occurrence -- including one inside a ``#`` comment, i.e. by writing the
name of the waiver rather than declaring it.
"""
uncommented = chr(10).join(
line.split("#", 1)[0] for line in text.splitlines()
)
if "pull_request_target" in uncommented and (
"ALLOW_PULL_REQUEST_TARGET:" not in uncommented
):
errors.append(
f"{path}: uses pull_request_target without ALLOW_PULL_REQUEST_TARGET rationale"
)


def _check_permissions_declared(path: Path, text: str, errors: list[str]) -> None:
# Minimal parser: require an explicit top-level permissions key before jobs.
"""Require a top-level permissions block AND check what it grants.

Presence alone was the whole test, so ``permissions: write-all``
satisfied it -- a declaration of total access counted as evidence of
least privilege.
"""
before_jobs = text.split("\njobs:", 1)[0]
if "\npermissions:" not in f"\n{before_jobs}":
errors.append(f"{path}: missing explicit top-level permissions block")
return
for number, line in enumerate(text.splitlines(), start=1):
stripped = line.split("#", 1)[0].strip()
if stripped in {"permissions: write-all", "permissions: read-all"}:
errors.append(
f"{path}:{number}: blanket '{stripped}' -- grant the "
f"individual scopes the workflow needs instead"
)


def main() -> int:
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ jobs:
url: https://pypi.org/p/liouscope
permissions:
id-token: write
attestations: write
contents: read
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Expand Down Expand Up @@ -103,6 +104,18 @@ jobs:
test "$SOURCE_VERSION" = "$EXPECTED_VERSION"
test "$HEAD_SHA" = "$TAG_SHA"
test "$EVENT_SHA" = "$TAG_SHA"
- name: Generate build provenance attestation
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: "dist/*"
- name: Verify build provenance attestation
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
for artifact in dist/*; do
gh attestation verify "$artifact" --repo "${{ github.repository }}"
done
- name: Publish via Trusted Publishing
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
Expand Down
18 changes: 14 additions & 4 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,18 @@ jobs:
# coworkerz-ci — repo-scoped GITHUB_TOKEN, docs.zizmor.sh). Das ist
# die praezisere Loesung gegenueber online-audits:false (Webrecherche
# 06-06): known-vulnerable-actions + stale-action-refs bleiben aktiv.
# privates Repo ohne GHAS: kein Action-internes Code-Scanning-Upload (wirft sonst
# "Resource not accessible"). Stattdessen Findings als inline-Annotationen.
advanced-security: false
annotations: true
# [2026-08-29] Auf true gesetzt. Die alte Begruendung lautete
# "privates Repo ohne GHAS" -- das Repo ist oeffentlich (gemessen:
# gh api repos/... --jq .visibility -> "public"), also steht das
# Code Scanning offen. Solange dies false war, wurden zizmor-Befunde
# nie hochgeladen: sie fehlten im Code Scanning nicht mangels
# Befunden, sondern mangels Upload.
advanced-security: true
# Mutually exclusive with advanced-security: the action refuses to
# start if both are set. Findings now go to Code Scanning, which is
# the point of turning advanced-security on -- inline annotations
# vanish with the run, a Code Scanning alert persists and can be
# triaged. Not caught locally: running zizmor directly does not
# exercise the action's own option validation.
annotations: false

11 changes: 8 additions & 3 deletions .github/zizmor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
# fremden privaten Repos lesen kann. SHA-Echtheit des Pins wird bei jedem Bump
# via gh api Pre/Post verifiziert. Alle uebrigen Online-Audits (known-
# vulnerable-actions, stale-action-refs) bleiben AKTIV.
rules:
impostor-commit:
disable: true
rules: {}
# [2026-08-29] impostor-commit WIEDER AKTIV. Die Abschaltung vom 06-06 war
# mit einem Crash am privaten Cross-Repo-Pin coworkerz-ci begruendet. Dieser
# Pin existiert nicht mehr -- die einzigen Treffer im Baum waren die
# Begruendungs-Kommentare selbst. Gegenprobe vor der Reaktivierung gefahren:
# zizmor mit aktiven Online-Audits meldet keine Befunde, alle 25 Pins sind
# upstream echt. Es ist der einzige Audit, der prueft, ob ein SHA-Pin
# ueberhaupt existiert; ohne ihn ist die gesamte Pin-Strategie ungeprueft.
Loading
Loading