fix: reject duplicate keys in execution catalogs
All checks were successful
ci / validate (push) Successful in 2m53s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0726e-5232-73f2-aaca-2c05ceb62efb
This commit is contained in:
tegwick 2026-09-06 09:31:49 +02:00
parent f5eec5b23f
commit 863fab7a3b
5 changed files with 97 additions and 1 deletions

View file

@ -17,6 +17,11 @@ assignment / channel / activity
## Profiles
Catalog YAML rejects duplicate mapping keys, including collisions introduced by
merge keys. Use one explicit value per key; later entries cannot override earlier
credential routes, limits, or rein capabilities. Errors identify the file and
line without printing the duplicate key or value.
List and validate every committed catalog profile, including its independently
declared runtime readiness:

View file

@ -62,9 +62,28 @@ def _default_data_dir(kind: str) -> Path:
return _source_root() / ("profiles" if kind == "profiles" else "registry/reins")
class _UniqueKeyLoader(yaml.SafeLoader):
"""Reject overwrites, including collisions introduced by YAML merges."""
def construct_mapping(self, node, deep=False):
mapping = super().construct_mapping(node, deep=deep)
seen = set()
for key_node, _ in node.value:
key = self.construct_object(key_node, deep=deep)
if key in seen:
mark = key_node.start_mark
# Key names and source snippets can themselves contain secrets.
raise yaml.YAMLError(
f"duplicate YAML key at line {mark.line + 1}, "
f"column {mark.column + 1}"
)
seen.add(key)
return mapping
def _read_yaml(path: Path) -> dict[str, Any]:
try:
data = yaml.safe_load(path.read_text())
data = yaml.load(path.read_text(), Loader=_UniqueKeyLoader)
except (OSError, yaml.YAMLError) as exc:
raise ProfileError(f"cannot read {path}: {exc}") from exc
if not isinstance(data, dict):

View file

@ -226,3 +226,45 @@ def test_incompatible_profile_or_rein_is_rejected(
with pytest.raises(IncompatibleProfileError, match=match):
ProfileCatalog(profiles, reins).resolve("harness.test@1.0.0")
@pytest.mark.parametrize("kind", ["profile", "rein"])
@pytest.mark.parametrize("nested", [False, True])
def test_duplicate_catalog_keys_are_rejected(tmp_path, kind, nested):
if kind == "profile":
content = _profile()
content += ("metadata:\n route: first\n route: second\n" if nested
else "credential_route_refs: [first]\ncredential_route_refs: [second]\n")
else:
content = _rein()
content = (content.replace("session_style: unattended",
"session_style: interactive\n session_style: unattended")
if nested else content + "status: disabled\n")
_write(tmp_path, "duplicate.yaml", content)
catalog = ProfileCatalog(profile_dir=tmp_path, rein_dir=tmp_path)
with pytest.raises(ProfileError, match="duplicate YAML key"):
catalog.profiles() if kind == "profile" else catalog.reins()
def test_yaml_merge_cannot_override_catalog_values(tmp_path):
_write(tmp_path, "profile.yaml", _profile(extra='''metadata:
defaults: &defaults
runtime: pinned
selected:
<<: *defaults
runtime: different
'''))
with pytest.raises(ProfileError, match="duplicate YAML key"):
ProfileCatalog(profile_dir=tmp_path).profiles()
def test_nonoverlapping_yaml_merge_remains_supported(tmp_path):
_write(tmp_path, "profile.yaml", _profile(extra='''metadata:
defaults: &defaults
runtime: pinned
selected:
<<: *defaults
host: local
'''))
profile = ProfileCatalog(profile_dir=tmp_path).profiles()[("harness.test", "1.0.0")]
assert profile.metadata["selected"] == {"runtime": "pinned", "host": "local"}

View file

@ -52,3 +52,18 @@ the fix and passes afterwards.
Validation: full suite 104 passed; profile catalog validation passed with
existing readiness unchanged. Reviewed credential owner update and refreshed
the proposed policy reference in docs/anthropic-workload-key.md.
## Reject ambiguous catalog YAML
```task
id: ADHOC-2026-09-06-T03
status: done
priority: medium
```
Follow-up repository review found that YAML silently overwrote duplicate keys
before profile validation. Both profile and rein descriptor loading now reject
duplicate keys at every mapping depth, including merge collisions. Disjoint
merges remain supported. Four regression cases reproduced silent acceptance
before the change. Full suite: 110 passed; committed catalog validation passes.
No residuals from this bounded fix; GLAS-WP-0012 retains the live-proof work.

View file

@ -234,3 +234,18 @@ by configuration, per-lane approval and positive/negative verification.
State Hub decisions are not a substitute for the durable authorization object.
SECRETS-WP-0009-T03 and this plan's T02 remain waiting; runtime pinning and
combined real proof remain required. No readiness change or real-key read.
## 2026-09-06 authorization contract and policy publication
Reviewed owner commits `7b4b9e3` and `083bee7` and FLEX-WP-0021. Gate-house
GH-DEC-2026-005 resolved the contract: secrets-engine now validates the
approval-claim and decision envelope separately and removed the incorrect
State Hub authority requirement. Flex-auth published
`secrets-engine.catalog-lane.lifecycle` v1; T01/T02 are done.
Remaining owner gates are real decision/digest verification (FLEX-WP-0021-T03),
consumer service deployment and handoff (T04/T05), approval-engine deployment,
production service identity and verified lane activation. Publication is not
deployment. T02 stays waiting, and runtime pinning and combined acceptance
remain required. No new owner inbox message or activation evidence was found
in this review.