security: record KeyCape custody caller reconciliation and native config proof
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Reject generated-only commits / generated-commit-guard (push) Successful in 8s

This commit is contained in:
codex 2026-10-13 19:49:24 +02:00
parent 873c595bbb
commit bb3e2db07e
4 changed files with 269 additions and 0 deletions

View file

@ -0,0 +1,23 @@
package config
import "testing"
func TestCustodyBootstrapNativeLoader(t *testing.T) {
cfg, err := Load("../../bootstrap-fixture.json")
if err != nil {
t.Fatal("bootstrap output failed native config parsing")
}
if cfg.PrivacyIDEA.AdminToken != "" || cfg.PrivacyIDEA.AdminTokenFile != "/etc/keycape-factor/admin-token" {
t.Fatal("credential source mismatch")
}
if cfg.PrivacyIDEA.Realm != "coulomb" || !cfg.PrivacyIDEA.RequireForAll {
t.Fatal("factor policy mismatch")
}
clients, err := cfg.Registrations()
if err != nil || len(clients) != 5 {
t.Fatal("bootstrap registrations did not survive parsing")
}
if cfg.LLDAP.BindPW == "" || cfg.Authelia.ClientSecret == "" {
t.Fatal("bootstrap credential fields missing")
}
}

View file

@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""Verify the synthetic bootstrap output with KeyCape's current native loader.
Only local source, synthetic credentials and disposable files are used. Requires
pytest, PyYAML, OpenSSL and Go with dependencies already cached. No kubectl from
PATH is executed: the fixture installs its recording stub in a private PATH.
"""
import argparse
import base64
import hashlib
import importlib.util
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
def digest(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--net-kingdom', type=Path, required=True)
parser.add_argument('--key-cape', type=Path, required=True)
args = parser.parse_args()
fixture = args.net_kingdom / 'tests/test_keycape_bootstrap.py'
spec = importlib.util.spec_from_file_location('bootstrap_fixture', fixture)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
with tempfile.TemporaryDirectory(prefix='keycape-bootstrap-native-') as directory:
root = Path(directory)
case_root = root / 'fixture'; case_root.mkdir()
case = module.setup.__wrapped__(case_root)
result = module.invoke(case)
if result.returncode:
raise RuntimeError('synthetic bootstrap failed')
writes = [c for c in module.calls(case) if c['args'][0] == 'create']
if len(writes) != 1:
raise RuntimeError('unexpected synthetic operation count')
manifest = json.loads(writes[0]['stdin'])
checkout = root / 'consumer'; checkout.mkdir()
shutil.copytree(args.key_cape / 'src', checkout / 'src',
ignore=shutil.ignore_patterns('.git', '__pycache__', '.pytest_cache'))
# Existing native config tests read only these public example fixtures.
(checkout / 'config').mkdir()
for name in ('dev-config.yaml', 'service-clients.example.yaml'):
shutil.copyfile(args.key_cape / 'config' / name, checkout / 'config' / name)
(checkout / 'src/bootstrap-fixture.json').write_bytes(base64.b64decode(manifest['data']['config.yaml']))
native_test = Path(__file__).with_name('keycape_bootstrap_native_test.go')
shutil.copyfile(native_test, checkout / 'src/internal/config/custody_bootstrap_test.go')
tested = subprocess.run(['go', 'test', '-count=1', './internal/config', './internal/adapters/privacyidea'],
cwd=checkout / 'src', capture_output=True, timeout=120,
env={**os.environ, 'GOPROXY': 'off', 'GOTOOLCHAIN': 'auto'})
if tested.returncode:
raise RuntimeError('native loader/adapter verification failed')
sources = ['src/internal/config/config.go', 'src/internal/adapters/privacyidea/config.go',
'src/internal/adapters/privacyidea/adapter.go',
'src/internal/adapters/privacyidea/credential_file_test.go']
print(json.dumps({'result': 'passed', 'bootstrap_fixture_sha256': digest(fixture),
'native_test_sha256': digest(native_test),
'consumer_sources': [{'path': p, 'sha256': digest(args.key_cape / p)} for p in sources],
'scope': 'Generated synthetic YAML parsed by native loader; local config and adapter suites. No live cluster or provider.'}, indent=2))
if __name__ == '__main__':
main()