feat(git): git-server abstraction vertical + GitHub App adapter - #126
Merged
Conversation
added 3 commits
July 24, 2026 10:28
…apter contract kit Provider-agnostic git-server vertical: IGitServer facade with concern-scoped ports (credentials, repositories, pipelines, CI configuration, environments, branch policies, access control, webhooks in/out, optional namespace provisioning), GitConnection/GitCredential closed union (redacted ToString), declarative GitServerCapabilities with EnsureSupported -> Git.CapabilityNotSupported (Result failure, never an exception), neutral GitWebhookEvent union, and a fail-fast NullGitServer stub. Compendium.Testing gains Git/InMemoryGitServer (full-fidelity, thread-safe fake with seed/CompleteRun/call-log hooks; secrets stored as names only) and GitServerContractTests, the capability-honest behavioral contract every adapter must pass — InMemoryGitServer is its first subscriber (12 green, 1 skip). Claude-Session: https://claude.ai/code/session_01VFDn7gCH7vdvT4eoNhsMLr
GitHub adapter for the git-server abstraction: hybrid Octokit + raw-REST executor (Actions variables, rulesets, environments, env secrets), GitHub App auth (RS256 app JWT <=9min, installation tokens cached per app+installation with 60s refresh skew, scoped mints bypass the cache, stale-JWT 401 retried once), libsodium sealed-box secret encryption, fail-closed HMAC-SHA256 webhook ingestor (constant-time compare) translating push/tag/PR/workflow_run and installation lifecycle events to the neutral GitWebhookEvent union. Capability matrix shipped as CAPABILITIES.md (packed in the nupkg): NamespaceProvisioning=None on github.com (enterprise-owner user token required, unreachable with App credentials), PipelineTrigger=Partial (workflow_dispatch returns no run id). Implementation types are internal; the package surface is AddGitHubGitServer + options. Grep-guard test keeps the source free of platform-specific literals. Also pins ServerUrl semantics in the abstraction: GitConnection.ServerUrl is the API base URL, not the web host root. 170 adapter tests (WireMock + Octokit-against-WireMock), 93.4% line coverage. ADR-0006 migration log: scheduled for extraction to compendium-adapter-github at the first stable tag. Claude-Session: https://claude.ai/code/session_01VFDn7gCH7vdvT4eoNhsMLr
Comment on lines
+50
to
+56
| foreach (var token in Forbidden) | ||
| { | ||
| if (line.Contains(token, StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| offenders.Add($"{Path.GetFileName(file)}:{lineNumber} -> '{token}'"); | ||
| } | ||
| } |
| { | ||
| // thisFile: tests/Unit/Compendium.Adapters.GitHub.Tests/NoSassyLiteralsTests.cs | ||
| var testProjectDir = Path.GetDirectoryName(thisFile)!; | ||
| var repoRoot = Path.GetFullPath(Path.Combine(testProjectDir, "..", "..", "..")); |
| // thisFile: tests/Unit/Compendium.Adapters.GitHub.Tests/NoSassyLiteralsTests.cs | ||
| var testProjectDir = Path.GetDirectoryName(thisFile)!; | ||
| var repoRoot = Path.GetFullPath(Path.Combine(testProjectDir, "..", "..", "..")); | ||
| return Path.Combine(repoRoot, "src", "Adapters", "Compendium.Adapters.GitHub"); |
…lipped IsTestProject dotnet test on the solution tried to run the shipped Compendium.Testing.dll as a test assembly (no Test.Sdk/testhost entry point) and failed CI. Pin IsTestProject=false explicitly: the package ships the git contract-test kit, it is not itself a test project. Claude-Session: https://claude.ai/code/session_01VFDn7gCH7vdvT4eoNhsMLr
Pomdapis
added a commit
that referenced
this pull request
Jul 24, 2026
…pter (#129) ## What New vertical `Compendium.Abstractions.Secrets` + in-tree adapter `Compendium.Adapters.Scaleway.SecretManager` (mirrors the git-server abstraction pattern, #126). **Abstraction** — `ISecretVault` facade with two concern-scoped ports: - `ISecretContainerService` (create/get/list-by-prefix+tags/delete) - `ISecretVersionService` (append immutable version, **access by explicit revision — no "latest" in the port**, list, enable/disable kill-switch, destroy) - Neutral `SecretVaultConnection`/`SecretVaultCredential` (redacted `ToString()`), `SecretMaterial` (never stringifies), declarative capabilities + `EnsureSupported`, `SecretVault.*` errors on the Result pattern, `NullSecretVault` fail-fast stub. - Design intent: `(secretId, revision)` is a **stable value reference** — which revision is *current* is the caller's metadata, so history is trustworthy and rollback is a re-pointing of references, portable across providers. **Testing kit** (`Compendium.Testing/Secrets`) — `InMemorySecretVault` full-fidelity fake + `SecretVaultContractTests` behavioral contract (~16 assertions families: monotonic revisions, immutability, kill-switch round-trip + idempotency, destroy reserves the revision number, prefix/tag listing, redaction). Swapping vault backends is safe iff the adapter passes this suite. **Scaleway adapter** — raw HTTP v1beta1 (no .NET SDK exists), `X-Auth-Token` per call, snake_case STJ models, uniform error mapping (409→ConflictExists, 429→Throttled+Retry-After metadata, ambiguous access 4xx disambiguated via version metadata into VersionDisabled/VersionNotFound/SecretNotFound), idempotent enable/disable, 64 KiB fail-fast, exactly-once writes (caller dedups by hash). `CAPABILITIES.md` packed. ## Why First brick of the Nexus "Config & Secrets v2" program (hybrid per-key delivery, org→project→app→env→version scoping, audit + one-click rollback). Scaleway SM is the v1 backend; the port + contract kit + documented migration path (copy data, rewrite refs, zero resolver change) is what makes the backend swappable later (in-house vault adapter). ## Tests - 34 abstraction tests (incl. InMemory contract subscription) + 16 WireMock adapter tests — all green. - Full solution test suite: green except 4 pre-existing environment-dependent integration failures (Kubernetes sandbox expecting a live-cluster behavior; unrelated to this purely additive change). ## Coordination - No shared-file friction expected: additive projects + 2-line `Compendium.sln` + 1 `ProjectReference` in `Compendium.Testing.csproj`. - Consumed next by Nexus branch `feat/config-secrets-v2` (needs the next preview tag on the train after merge). https://claude.ai/code/session_01F9hzMWYy7nKKhf6B2XxznV --------- Co-authored-by: sacha <sacha@scojhconsult.com>
This was referenced Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New provider-agnostic git-server vertical for the framework, plus its first adapter.
Compendium.Abstractions.Git—IGitServerfacade (Providerdiscriminator + declarativeGitServerCapabilities) with concern-scoped ports: credentials (IGitCredentialBroker: mint short-lived tokens, validate, resolve/list app installations), repositories (create-from-template, commits/branches/tags, releases), pipelines, CI secrets/variables (repo/namespace/environment scopes), deployment environments, branch policies (neutral → rulesets), teams & repo roles, outgoing webhooks + a pure fail-closed inboundIGitWebhookIngestor, and optional namespace provisioning.GitConnection/GitCredentialclosed union (token material redacted inToString()). Unsupported capability ⇒ResultfailureGit.CapabilityNotSupported— never an exception. Ships a fail-fastNullGitServerfor unconfigured hosts.Compendium.Adapters.GitHub(in-tree; ADR-0006 migration log schedules extraction tocompendium-adapter-githubat the first stable tag) — GitHub App auth (RS256 app JWT ≤9 min → installation tokens, cached per (app, installation) with 60 s refresh skew; scoped mints bypass the cache), hybrid Octokit + raw-REST executor for Actions variables/rulesets/environments/env secrets, libsodium sealed-box secret encryption, HMAC-SHA256 webhook ingestor (constant-time compare) covering push/tag/PR/workflow_run/installation lifecycle. Capability matrix inCAPABILITIES.md(packed in the nupkg). Implementation internal; public surface =AddGitHubGitServer+ options. Grep-guard test keeps platform-specific literals out (public package).Compendium.Testing—InMemoryGitServerfull-fidelity fake (secrets stored as names only, seed/CompleteRun/call-log hooks) +GitServerContractTests, the behavioral contract every adapter must pass; the fake is its first subscriber.Tests
Notes for review
GitConnection.ServerUrlsemantics pinned: API base URL (not web host root).v1.0.5-preview.2.https://claude.ai/code/session_01VFDn7gCH7vdvT4eoNhsMLr