feat: profiles.json v2 parser with validation invariants (#103)
Add version-2 support to gitea_config: environment -> service -> identity
hierarchy flattened at load into v1-shaped profiles keyed by the canonical
dotted address {env}.{service}.{identity}, with aliases for legacy names
(mdcps, prgs-author, prgs-reviewer) and service-level defaults inherited by
identities.
Fail-closed validation: missing required version (v1 files must now declare
version: 1), unknown versions, malformed environment/service/identity
structure, dotted segment names, missing base_url, missing auth reference,
inline secrets in identities or auth entries, alias/address selector
conflicts, aliases to unknown targets, and unqualified operations that
cannot be normalized safely. TBD-* usernames fail closed at selection
without blocking other identities in the file.
Reviewer-identity deadlock rule enforced at load: any identity allowed
gitea.pr.approve or gitea.pr.merge must forbid gitea.pr.create and
gitea.branch.push (prevents the PR #102-style self-authored-PR deadlock).
Selector resolution is strict: exact alias -> exact dotted address -> fail
closed; no fuzzy matching. Minimal operation normalization only (the known
v1 unqualified Gitea ops and single-word non-Gitea ops); the full table and
enforcement matrix remain issue #106.
Tests: new tests/test_config_v2.py (29 cases) covering the acceptance
criteria; test_config.py missing-version case flipped to fail-closed per
the issue. resolve_token/auth_source_name proven against flattened v2
profiles.
Refs #100. Closes #103.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -127,11 +127,14 @@ class TestLoadSelect(_ConfigBase):
|
||||
gitea_config.resolve_profile()
|
||||
self.assertIn("version", str(ctx.exception))
|
||||
|
||||
def test_missing_version_defaults_ok(self):
|
||||
def test_missing_version_fails_closed(self):
|
||||
# Changed by #103: an unversioned config is ambiguous between the v1
|
||||
# and v2 shapes, so the loader now refuses to guess.
|
||||
self._write({"profiles": {"prgs": {"base_url": "https://x"}}})
|
||||
with patch.dict(os.environ, self._env("prgs"), clear=True):
|
||||
self.assertEqual(
|
||||
gitea_config.resolve_profile()["base_url"], "https://x")
|
||||
with self.assertRaises(gitea_config.ConfigError) as ctx:
|
||||
gitea_config.resolve_profile()
|
||||
self.assertIn("version", str(ctx.exception))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user