refactor(manifest): key git config by host
This commit is contained in:
@@ -269,12 +269,14 @@ cred_proxy:
|
||||
token_ref: GITEA_TOKEN
|
||||
role: [git-insteadof, tea-login]
|
||||
git:
|
||||
- Name: claude-bottle
|
||||
Upstream: ssh://git@gitea.dideric.is:30009/didericis/claude-bottle.git
|
||||
IdentityFile: ~/.ssh/gitea-delos-2.pem
|
||||
ExtraHosts:
|
||||
gitea.dideric.is: 100.78.141.42
|
||||
KnownHostKey: ssh-rsa AAAAB3...
|
||||
remotes:
|
||||
gitea.dideric.is:
|
||||
Name: claude-bottle
|
||||
Upstream: ssh://git@gitea.dideric.is:30009/didericis/claude-bottle.git
|
||||
IdentityFile: ~/.ssh/gitea-delos-2.pem
|
||||
ExtraHosts:
|
||||
gitea.dideric.is: 100.78.141.42
|
||||
KnownHostKey: ssh-rsa AAAAB3...
|
||||
egress:
|
||||
allowlist:
|
||||
- example.com
|
||||
|
||||
@@ -191,9 +191,11 @@ egress:
|
||||
- host: api.anthropic.com
|
||||
|
||||
git:
|
||||
- Name: throwaway
|
||||
Upstream: ssh://git@127.0.0.1:22/throwaway.git
|
||||
IdentityFile: ~/.ssh/cb-test-key # fixture key
|
||||
remotes:
|
||||
127.0.0.1:
|
||||
Name: throwaway
|
||||
Upstream: ssh://git@127.0.0.1:22/throwaway.git
|
||||
IdentityFile: ~/.ssh/cb-test-key # fixture key
|
||||
---
|
||||
```
|
||||
|
||||
|
||||
@@ -105,23 +105,17 @@ overlay it. For each field on `Bottle`:
|
||||
| Field | Type | Merge |
|
||||
|--------------|-----------------------|---------------------------------------------|
|
||||
| `env` | `Mapping[str, str]` | dict merge, child wins on key collision |
|
||||
| `git` | `tuple[GitEntry,…]` | full replace if child declares `git:` |
|
||||
| `git_user` | `GitUser` | child overlay: child's non-empty fields win |
|
||||
| `git.user` | `GitUser` | child overlay: child's non-empty fields win |
|
||||
| `git.remotes`| `tuple[GitEntry,…]` | dict merge by host, child wins |
|
||||
| `egress` | `EgressConfig` | full replace if child declares `egress:` |
|
||||
| `supervise` | `bool` | full replace if child declares `supervise:` |
|
||||
|
||||
Why full-replace for the list-valued fields (`git[]`,
|
||||
`egress.routes[]`):
|
||||
Why full-replace for `egress.routes[]`:
|
||||
|
||||
- **Ordering matters.** Egress route ordering is part of the
|
||||
match semantics (first matching host wins). Merging two
|
||||
ordered lists by name introduces "where does the child's route
|
||||
go?" ambiguity.
|
||||
- **Name collisions are ambiguous.** If parent has
|
||||
`git: [{Name: foo, Upstream: A}]` and child has `git:
|
||||
[{Name: foo, Upstream: B}]`, "merge" could mean override-B or
|
||||
error-on-collision. Full-replace makes the operator's
|
||||
intent explicit.
|
||||
- **Simpler precedence.** "Child declares X → X wins, full
|
||||
stop" is one sentence; partial merges need a table per list.
|
||||
|
||||
@@ -129,9 +123,15 @@ The `env` dict is the one exception because dict-merge has no
|
||||
ordering concern and dict-keyed overrides are the obvious user
|
||||
expectation. (Same model as shell `export` precedence.)
|
||||
|
||||
The `git_user` dataclass-overlay (each non-empty field wins
|
||||
individually) is so a parent can declare `git_user.name` and a
|
||||
child can add just `git_user.email`. The default `GitUser()`
|
||||
`git.remotes` is also keyed, so it follows dict-style inheritance:
|
||||
children can override one host without restating every remote. The
|
||||
remote entry is replaced as a whole on host collision because
|
||||
`Upstream`, `IdentityFile`, `KnownHostKey`, and `ExtraHosts` are
|
||||
tightly coupled.
|
||||
|
||||
The `git.user` dataclass-overlay (each non-empty field wins
|
||||
individually) is so a parent can declare `git.user.name` and a
|
||||
child can add just `git.user.email`. The default `GitUser()`
|
||||
fields are empty strings, which are treated as "not set" for
|
||||
overlay purposes — same `is_empty()` predicate the provisioner
|
||||
uses.
|
||||
@@ -191,7 +191,7 @@ moot because there's only one bottle source.
|
||||
- Implement `_merge(parent: Bottle, child_raw: dict, name: str)
|
||||
-> Bottle` with the rules table above.
|
||||
- Unit tests: simple two-bottle extends, env merge with
|
||||
collision, list-replace for git + egress, git_user overlay,
|
||||
collision, host-keyed git remote merge, egress list-replace, git.user overlay,
|
||||
supervise override, missing parent dies, cycle dies, deeper
|
||||
chains (A extends B extends C).
|
||||
3. **Docs.** Add an `extends:` example to the README's manifest
|
||||
|
||||
Reference in New Issue
Block a user