Skip to content

feat(git): git-server abstraction vertical + GitHub App adapter - #126

Merged
Pomdapis merged 4 commits into
mainfrom
feat/git-server-abstraction
Jul 24, 2026
Merged

feat(git): git-server abstraction vertical + GitHub App adapter#126
Pomdapis merged 4 commits into
mainfrom
feat/git-server-abstraction

Conversation

@Pomdapis

Copy link
Copy Markdown
Contributor

Summary

New provider-agnostic git-server vertical for the framework, plus its first adapter.

  • Compendium.Abstractions.GitIGitServer facade (Provider discriminator + declarative GitServerCapabilities) 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 inbound IGitWebhookIngestor, and optional namespace provisioning. GitConnection/GitCredential closed union (token material redacted in ToString()). Unsupported capability ⇒ Result failure Git.CapabilityNotSupported — never an exception. Ships a fail-fast NullGitServer for unconfigured hosts.
  • Compendium.Adapters.GitHub (in-tree; ADR-0006 migration log schedules extraction to compendium-adapter-github at 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 in CAPABILITIES.md (packed in the nupkg). Implementation internal; public surface = AddGitHubGitServer + options. Grep-guard test keeps platform-specific literals out (public package).
  • Compendium.TestingInMemoryGitServer full-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

  • Abstraction: 148 passed / 1 legitimate skip — 100% line + branch coverage.
  • Adapter: 170 passed — 93.4% line coverage (gate ≥90%).
  • Deterministic; no live GitHub calls in CI (WireMock; Octokit pointed at WireMock).

Notes for review

  • GitConnection.ServerUrl semantics pinned: API base URL (not web host root).
  • New central pins: Octokit 14.0.0, Sodium.Core 1.4.0, WireMock.Net 1.6.9.
  • Downstream consumer (Nexus org-level GitHub-App connections, no user PATs) starts on the next preview tag: v1.0.5-preview.2.

https://claude.ai/code/session_01VFDn7gCH7vdvT4eoNhsMLr

sacha 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
Pomdapis merged commit e49f078 into main Jul 24, 2026
5 checks passed
@Pomdapis
Pomdapis deleted the feat/git-server-abstraction branch July 24, 2026 09:52
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant