@colony2/gitvend 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
A Go Git/HTTPS gateway with permissions carried in signed JWTs. Agents use ordinary Git and one gateway credential across their assigned repositories. The gateway holds a shared upstream token and enforces repository, ref-discovery, branch-write, tag and repository-creation permissions before forwarding requests.
|
|
4
4
|
|
|
5
|
-
Implemented for GitHub and GitHub Enterprise-compatible APIs. Client and upstream Git connections use HTTPS; fetch/ref lookup requires protocol v2, while pushes use Git's normal receive-pack format. The service does not require a GitHub App.
|
|
5
|
+
Implemented for GitHub and GitHub Enterprise-compatible APIs. Client and upstream Git connections use HTTPS; fetch/ref lookup requires protocol v2, while pushes use Git's normal receive-pack format. The service does not require a GitHub App. The gateway is stateless: it needs configuration, public verification keys and upstream credentials, with no database or writable state volume. Multiple instances can serve the same agents.
|
|
6
6
|
|
|
7
7
|
This guide takes an operator from configuring a gateway to giving an agent a credential, cloning a repository, and pushing an allowed branch.
|
|
8
8
|
|
|
9
|
-
[Install](#install) · [Set up the gateway](#set-up-the-gateway) · [Issue a credential](#issue-an-agent-credential) · [Agent usage](#use-gitvend-as-an-agent) · [Permissions](#permission-strings) · [Operations](#provisioning-and-audit) · [Troubleshooting](#troubleshooting) · [CLI reference](#cli-reference)
|
|
9
|
+
[Install](#install) · [Docker Compose](docs/docker-compose.md) · [Set up the gateway](#set-up-the-gateway) · [Issue a credential](#issue-an-agent-credential) · [Agent usage](#use-gitvend-as-an-agent) · [Permissions](#permission-strings) · [Operations](#provisioning-and-audit) · [Troubleshooting](#troubleshooting) · [CLI reference](#cli-reference)
|
|
10
10
|
|
|
11
11
|
## How credentials and permissions fit together
|
|
12
12
|
|
|
@@ -42,6 +42,15 @@ gitvend version
|
|
|
42
42
|
|
|
43
43
|
For a Go installation, add `$(go env GOPATH)/bin` to your `PATH` if needed. The npm wrapper requires Node 22+ and `tar`. Install scripts must be enabled so it can download the binary from GitHub Releases. Release builds report their release version; local builds report their Git revision when available.
|
|
44
44
|
|
|
45
|
+
### Docker Compose
|
|
46
|
+
|
|
47
|
+
The [Compose deployment guide](docs/docker-compose.md) covers a container image,
|
|
48
|
+
automatic signing-key initialization on persistent volumes, a mounted GitHub
|
|
49
|
+
token, and on-demand JWT issuance. Only the gateway stays running; the private
|
|
50
|
+
signing key is available to initialization and issuer containers, never mounted
|
|
51
|
+
into the gateway. The default stack binds HTTP to host loopback for use behind
|
|
52
|
+
an HTTPS reverse proxy.
|
|
53
|
+
|
|
45
54
|
## Build and verify
|
|
46
55
|
|
|
47
56
|
Requires Go 1.25+ and Git for the integration tests. Supported server platforms are Linux and macOS. Run these commands from the source checkout's root:
|
|
@@ -91,7 +100,7 @@ Keep `var/signing.key` on that machine. Copy **only** `signing.pub` to `var/sign
|
|
|
91
100
|
|
|
92
101
|
### 3. Configure and start the server
|
|
93
102
|
|
|
94
|
-
On the gateway,
|
|
103
|
+
On the gateway, prepare the public-key directory and copy the [configuration template](examples/gitvend.json) from the source checkout or release archive. If installed through Go or npm, obtain that template separately from this repository:
|
|
95
104
|
|
|
96
105
|
```sh
|
|
97
106
|
mkdir -p var
|
|
@@ -104,7 +113,6 @@ Edit `gitvend.json` using this checklist:
|
|
|
104
113
|
| --- | --- |
|
|
105
114
|
| `listen` | `0.0.0.0:8443` to accept connections on the gateway's network interfaces. The template binds to `127.0.0.1:8443` for local access. |
|
|
106
115
|
| `tls_cert`, `tls_key` | Readable certificate/key files for `git-gateway.example`, trusted by the agents. |
|
|
107
|
-
| `state_file` | A persistent, writable database path; default `var/gitvend.db`. |
|
|
108
116
|
| `keys[].public_key_file` | The public key installed in step 2. |
|
|
109
117
|
| `keys[].owners` and `providers[].allowed_owners` | Your lowercase organization names in both places. |
|
|
110
118
|
| `providers[].credential.secret_ref` | `env:GITHUB_TOKEN` or the mounted token file reference. |
|
|
@@ -159,7 +167,7 @@ gitvend sign \
|
|
|
159
167
|
-output var/agent-47.jwt
|
|
160
168
|
```
|
|
161
169
|
|
|
162
|
-
Alternatively, pass `-grant examples/grant.json`. The file contains `v
|
|
170
|
+
Alternatively, pass `-grant examples/grant.json`. The file contains `v` and the `permissions` array. Permissions follow repository names, including future repositories with matching names; there are no repository-ID bindings. `-output` replaces the token file atomically with permissions `0600`; without it, `sign` writes the token to stdout. `keygen` refuses to overwrite existing key files.
|
|
163
171
|
|
|
164
172
|
JWTs use Ed25519 signatures (`alg=EdDSA`, `typ=gitvend+jwt`). Verification requires the configured issuer, key ID and audience plus subject, token ID, issued-at, not-before, expiry and grant version. Unknown fields, duplicate JSON keys, unsupported algorithms and malformed rules are rejected. The gateway needs no issued-token database and never contacts the issuer on a Git request.
|
|
165
173
|
|
|
@@ -275,7 +283,7 @@ gitvend explain \
|
|
|
275
283
|
-action ref.update
|
|
276
284
|
```
|
|
277
285
|
|
|
278
|
-
The example returns `"allowed": false`. `explain` evaluates only the rules you pass; include applicable deny rules yourself. It does not load server configuration, verify a JWT, or check GitHub permissions. A valid explanation command exits successfully even for a denied decision; inspect `allowed`. A `repo.create` explanation evaluates the `c` permission only, not the additional branch-overlap
|
|
286
|
+
The example returns `"allowed": false`. `explain` evaluates only the rules you pass; include applicable deny rules yourself. It does not load server configuration, verify a JWT, or check GitHub permissions. A valid explanation command exits successfully even for a denied decision; inspect `allowed`. A `repo.create` explanation evaluates the `c` permission only, not the additional branch-overlap or upstream checks.
|
|
279
287
|
|
|
280
288
|
## Provisioning and audit
|
|
281
289
|
|
|
@@ -283,23 +291,33 @@ Repository creation is opt-in twice: the provider must set `allow_creation: true
|
|
|
283
291
|
|
|
284
292
|
Creation occurs during receive-pack discovery. Consequently, `git push --dry-run`, abandoned pushes and later branch-policy rejections may leave empty repositories. Clone/fetch never creates repositories. Direct receive-pack POSTs cannot create missing repositories. Created repositories are private and uninitialized; the gateway never changes an existing repository's visibility, deletes it, or silently seeds `main`.
|
|
285
293
|
|
|
286
|
-
|
|
294
|
+
Concurrent creation is coordinated by the forge's repository-name uniqueness. Different gateway instances may both attempt creation; after a conflict or ambiguous response, gitvend looks up the name and checks that the resulting repository is private and matches the requested owner/name. It never changes an existing repository's visibility. If the outcome cannot be confirmed, the request fails with 503; a later normal push discovery performs a fresh lookup. There are no background reconciliation jobs, creation quotas or stored attempts.
|
|
295
|
+
|
|
296
|
+
Permissions follow repository names. Deleting and recreating a repository under the same name leaves a matching JWT grant applicable to that name. Gitvend does not enroll repositories or pin their IDs.
|
|
297
|
+
|
|
298
|
+
### Audit logs
|
|
287
299
|
|
|
288
|
-
|
|
300
|
+
`gitvend serve` emits newline-delimited JSON audit records on **stdout** and operational logs on stderr. Collect stdout with your process supervisor or logging service. Gitvend keeps no audit database or outbox and has no `audit` command.
|
|
289
301
|
|
|
290
|
-
|
|
302
|
+
Each JSON record has an `audit` object containing request ID, issuer/subject, token ID, repository, operation and outcome when available. A request can emit an `admitted` event before contacting the upstream and a final outcome with the same `audit.id`. Creation events have a separate ID and an `audit.parent_id` linking them to the Git request's `X-Request-ID` response header. JWT strings, upstream tokens and pack contents are excluded.
|
|
303
|
+
|
|
304
|
+
For example, inspect an existing log export with `jq`:
|
|
291
305
|
|
|
292
306
|
```sh
|
|
293
|
-
|
|
307
|
+
jq -c 'select(.audit.operation == "git-receive-pack") | .audit' audit.jsonl
|
|
294
308
|
```
|
|
295
309
|
|
|
296
|
-
|
|
310
|
+
Push audit distinguishes `accepted`, `rejected`, `partial` and `unknown`; HTTP 200 alone is not success. Creation outcomes are `created`, `reconciled`, `rejected` or `unknown` and do not claim that a subsequent push succeeded. A crash can leave an admission with no final record. Log delivery is best-effort, with retention and durability handled by your logging infrastructure. Inspect the remote refs before retrying an interrupted push; gitvend never retries a push automatically.
|
|
311
|
+
|
|
312
|
+
### Multiple instances
|
|
313
|
+
|
|
314
|
+
Run any number of instances behind the same HTTPS endpoint with matching configuration, trusted keys and credentials. No shared disk, database, distributed lock or sticky session is required. Configuration/key rotations must reach each instance; a reload on one instance does not update others. `max_concurrent` and request limits apply per instance. If you need fleet-wide rate limits or creation budgets, enforce them outside gitvend. A metrics export endpoint is not implemented.
|
|
297
315
|
|
|
298
316
|
## Configuration and limits
|
|
299
317
|
|
|
300
|
-
Run the service under a supervisor with a consistent working directory and
|
|
318
|
+
Run the service under a supervisor with a consistent working directory and readable configuration/key/credential files. The running gateway can use a read-only filesystem; operator commands such as `keygen` and `sign -output` still write their explicitly requested files. `SIGTERM` or Ctrl-C starts graceful shutdown with a 10-second drain period; transfers still running afterward are closed.
|
|
301
319
|
|
|
302
|
-
Send `SIGHUP` to atomically reload public keys, issuer ceilings, upstream token files, deny rules and limits. A failed reload preserves the last valid configuration. Changes to the listener
|
|
320
|
+
Send `SIGHUP` to atomically reload public keys, issuer ceilings, upstream token files, deny rules and limits. A failed reload preserves the last valid configuration. Changes to the listener or TLS paths require restart. Replacing an environment variable requires restarting the process. Config reload does not rewrite credentials already in use by an admitted operation.
|
|
303
321
|
|
|
304
322
|
For signing-key rotation, add the new public key under a new `id`, reload, and issue tokens with that `-kid`. Keep the old key configured until its tokens have expired, including clock tolerance, if they should remain valid; then remove it and reload. To rotate an upstream file token, replace that file and reload; the gateway reads upstream credentials at startup/reload, unlike the agent helper, which reads its JWT for each credential request.
|
|
305
323
|
|
|
@@ -314,18 +332,16 @@ Important defaults:
|
|
|
314
332
|
| `max_pack_bytes` | 1 GiB incoming encoded and decoded request body limits |
|
|
315
333
|
| `max_concurrent` | 64 active Git requests |
|
|
316
334
|
| `request_timeout_seconds` | 1,800 |
|
|
317
|
-
| `creates_per_subject_per_day` | 100, grouped by issuer and subject |
|
|
318
|
-
| `creates_per_owner_per_day` | 1,000 |
|
|
319
335
|
|
|
320
336
|
The HTTP server accepts up to 64 KiB of headers. Basic authentication expands a JWT by roughly one-third, so ingress limits must accommodate the configured token budget too. Use `sign -max-token-bytes` with the same budget as the gateway. Oversized grants are rejected, never truncated or broadened.
|
|
321
337
|
|
|
322
|
-
|
|
338
|
+
Incoming packs are streamed after their command prefix passes authorization. Pack contents are not inspected for file/path rules or commit ancestry.
|
|
323
339
|
|
|
324
|
-
|
|
340
|
+
Ordinary clone/fetch/push requests need only the upstream Git endpoint. REST lookups are used during push discovery when both the configuration and JWT permit automatic creation. Those API calls share the upstream credential's rate limit; gitvend does not coordinate rate limits across instances.
|
|
325
341
|
|
|
326
342
|
## Troubleshooting
|
|
327
343
|
|
|
328
|
-
Start with `gitvend version`, `/healthz`, and `git ls-remote --heads` as shown above. Use the HTTP `X-Request-ID` for authenticated Git requests to correlate a failure with the
|
|
344
|
+
Start with `gitvend version`, `/healthz`, and `git ls-remote --heads` as shown above. Use the HTTP `X-Request-ID` for authenticated Git requests to correlate a failure with the collected audit logs. Avoid sharing raw credentials or full authorization headers when collecting diagnostics.
|
|
329
345
|
|
|
330
346
|
| Symptom | What to check |
|
|
331
347
|
| --- | --- |
|
|
@@ -336,16 +352,16 @@ Start with `gitvend version`, `/healthz`, and `git ls-remote --heads` as shown a
|
|
|
336
352
|
| HTTP 403 / `push denied for ...` | Inspect the exact destination ref, matching `r` plus `w`/`d` grants, issuer/owner limits and gateway denies. The sample denies writes to main/master. |
|
|
337
353
|
| No refs shown; clone cannot find main or remote HEAD | The requested branch may be absent or hidden. Use an explicitly permitted branch with `--branch`; new scratch repos may have only `agents/47/start`. |
|
|
338
354
|
| HTTP 404 / unsupported route or missing repository | Use `/alias/owner/repo.git`, check allowed owners, and verify the upstream identity can see the repository. Only authorized push discovery can create a missing repo. |
|
|
339
|
-
| Missing repo is not created | Check `allow_creation`, `c`, overlapping branch `rw`, owner limits
|
|
355
|
+
| Missing repo is not created | Check `allow_creation`, `c`, overlapping branch `rw`, owner limits and upstream organization permissions. Check the audit logs for an unconfirmed create attempt. |
|
|
340
356
|
| HTTP 429 / gateway busy | The concurrent-request limit is reached. Wait for active requests to finish and retry. |
|
|
341
|
-
| HTTP 409 /
|
|
342
|
-
| HTTP 502 / upstream request refused or
|
|
343
|
-
| HTTP 503 /
|
|
357
|
+
| HTTP 409 / private profile violation | A creation attempt resolved to a non-private repository. Investigate the upstream name/visibility; gitvend will not alter it automatically. |
|
|
358
|
+
| HTTP 502 / upstream request refused or lookup failed | Check the upstream token, Git/API base URLs and forge availability/rate limits. A gateway JWT cannot overcome upstream restrictions. |
|
|
359
|
+
| HTTP 503 / repository creation unconfirmed | The create attempt and follow-up lookup could not confirm success. Check upstream access/availability, then retry normal push discovery. |
|
|
344
360
|
| HTTP 431 or large token rejected at ingress | Align ingress header limits, server `max_token_bytes` and signing `-max-token-bytes`; Basic authentication expands the token. |
|
|
345
361
|
| Push disconnects or audit outcome is `unknown` | Fetch or inspect the permitted remote ref before deciding whether to retry; some or all updates may already have reached GitHub. |
|
|
346
362
|
| npm-installed command reports a missing binary | Check whether install scripts were disabled and whether release downloads were reachable; after fixing that, run `npm rebuild @colony2/gitvend`. |
|
|
347
363
|
|
|
348
|
-
|
|
364
|
+
When upgrading an earlier checkout, remove `state_file`, `creates_per_subject_per_day` and `creates_per_owner_per_day` from configuration. Remove `bindings` from grant files and reissue any JWTs containing that field. Unknown fields are rejected. Old database files are no longer read by the gateway.
|
|
349
365
|
|
|
350
366
|
## CLI reference
|
|
351
367
|
|
|
@@ -355,17 +371,16 @@ For commands that take flags, use `-h` to list them, for example `gitvend sign -
|
|
|
355
371
|
| --- | --- |
|
|
356
372
|
| `gitvend version` | Show the release version or development build identity. |
|
|
357
373
|
| `gitvend serve -config gitvend.json` | Start the gateway. |
|
|
358
|
-
| `gitvend keygen -private signing.key -public signing.pub` | Generate a new issuer key pair without overwriting existing files. |
|
|
374
|
+
| `gitvend keygen -private signing.key -public signing.pub` | Generate a new issuer key pair without overwriting existing files. Add `-if-missing` to validate/reuse persistent keys or recover a missing public key. Parent directories must exist. |
|
|
359
375
|
| `gitvend sign` | Issue a JWT; requires `-key`, `-kid`, `-issuer`, `-subject` and a grant. Use repeated `-permission` **or** `-grant`, not both; `-output` writes an atomic token file. |
|
|
360
376
|
| `gitvend credential` | Git helper; specify `-host` and exactly one of `-token-file` or `-token-env`, followed by `get`, `store` or `erase`. |
|
|
361
377
|
| `gitvend explain` | Explain explicit `-permission` rules for a `-repo`, optional `-ref`, and `-action`. Ref values are fully qualified, such as `refs/heads/main`. |
|
|
362
|
-
| `gitvend audit -state var/gitvend.db` | Print the stored audit journal while the gateway is stopped. |
|
|
363
378
|
|
|
364
379
|
`explain` actions are `repo.read`, `repo.create`, `ref.discover`, `ref.create`, `ref.update` and `ref.delete`. The default is `ref.update`.
|
|
365
380
|
|
|
366
381
|
## Compatibility and verification scope
|
|
367
382
|
|
|
368
|
-
The automated tests cover real Git v2 discovery/clone/fetch, shallow and partial clones, known-hash reads, standard pushes, ref filtering, mixed denied pushes, tags, deletion, force updates, atomic and partial push outcomes, creation races/recovery, JWT tampering/expiry/size, secret/key reloads,
|
|
383
|
+
The automated tests cover real Git v2 discovery/clone/fetch, shallow and partial clones, known-hash reads, standard pushes, ref filtering, mixed denied pushes, tags, deletion, force updates, atomic and partial push outcomes, creation races/recovery, JWT tampering/expiry/size, secret/key reloads, independent replicas, name-based permissions and malformed/gzip requests. Parser fuzz targets and race checks are included.
|
|
369
384
|
|
|
370
385
|
Supported object format is SHA-1. SSH, Git LFS, Git protocol v0/v1 fetch, signed push certificates, push options, named shallow exclusions, ref-in-want, offloaded pack/bundle URLs and provider-managed ref namespaces are rejected or not advertised. Branch writes can include workflow files; CI execution and secrets remain governed by the forge's configuration. GitHub branch rules continue to apply to the shared upstream identity.
|
|
371
386
|
|
|
@@ -375,12 +390,12 @@ The original requirements and implementation tradeoffs are in [the design](docs/
|
|
|
375
390
|
|
|
376
391
|
## Release automation
|
|
377
392
|
|
|
378
|
-
The [release workflow](.github/workflows/release.yaml) follows [c2j's release pattern](https://github.com/colony-2/c2j/blob/main/.github/workflows/release.yaml). Successful pushes to `main` in the `colony-2` organization run the test suite, automatically bump and push a version tag (patch by default), build four binaries, and publish GitHub release archives and checksums. It then publishes `@colony2/gitvend` to npm after installing and smoke-testing the packed wrapper against the published assets.
|
|
393
|
+
The [release workflow](.github/workflows/release.yaml) follows [c2j's release pattern](https://github.com/colony-2/c2j/blob/main/.github/workflows/release.yaml). Successful pushes to `main` in the `colony-2` organization run the test suite, automatically bump and push a version tag (patch by default), build four binaries, and publish GitHub release archives and checksums. It then publishes `@colony2/gitvend` to npm after installing and smoke-testing the packed wrapper against the published assets. It also publishes Linux amd64/arm64 container images to `ghcr.io/colony-2/gitvend` with the release tag and `latest`, using `GITHUB_TOKEN` with package-write permission.
|
|
379
394
|
|
|
380
395
|
GitHub release/tag publication uses the workflow's `GITHUB_TOKEN`. Configure npm trusted publishing for `colony-2/gitvend`, workflow `release.yaml`, or provide an `NPM_TOKEN` with publishing access to `@colony2/gitvend`. The npm package must exist and its trusted publisher must be configured before token-free publication can work; bootstrap it with a token if needed.
|
|
381
396
|
|
|
382
397
|
macOS signing/notarization is optional. Set all five secrets to enable it: `MACOS_SIGN_P12`, `MACOS_SIGN_PASSWORD`, `APPLE_API_ISSUER`, `APPLE_API_KEY_ID`, and `APPLE_API_KEY`. No signing secrets skips this step; a partial configuration fails the build. Signing requires the matching Apple certificate and notarization credentials.
|
|
383
398
|
|
|
384
|
-
The reusable [test workflow](.github/workflows/test.yml) runs Go race tests, vet, parser fuzzing
|
|
399
|
+
The reusable [test workflow](.github/workflows/test.yml) runs Go race tests, vet, parser fuzzing, npm installer tests, and the Docker Compose smoke test. Run the installer tests locally with `npm test --prefix npm/gitvend` and the container checks with `make test-compose`. Release archive smoke tests also check all checksums and run the native binary's `version` command before upload.
|
|
385
400
|
|
|
386
401
|
Copied release tooling retains its upstream Apache-2.0 license and attribution in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). This repository does not yet declare a project-wide license; npm metadata uses `UNLICENSED`.
|
package/package.json
CHANGED