JSON-Rohbericht maschinenlesbar
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 4914,
"has_wiki": false,
"homepage": null,
"languages": {
"Go": 423112,
"Shell": 1196,
"Makefile": 3529,
"Go Template": 323
},
"pushed_at": "2026-07-19T22:42:10Z",
"created_at": "2017-07-02T00:23:45Z",
"owner_type": "Organization",
"updated_at": "2026-07-19T22:41:42Z",
"description": "Secure and easy ssh certs via an ssh-agent and CA ",
"is_archived": false,
"is_disabled": false,
"license_spdx": null,
"default_branch": "main",
"license_spdx_raw": "NOASSERTION",
"primary_language": "Go",
"significant_languages": [
"Go"
]
},
"owner": {
"blog": null,
"name": null,
"type": "Organization",
"login": "epithet-ssh",
"company": null,
"location": null,
"followers": 0,
"avatar_url": "https://avatars.githubusercontent.com/u/57017967?v=4",
"created_at": "2019-10-25T20:01:51Z",
"is_verified": null,
"public_repos": 11,
"account_age_days": 2467
},
"license": {
"state": "custom",
"spdx_id": null,
"raw_spdx": "NOASSERTION",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.17.3",
"kind": "patch",
"published_at": "2026-07-19T22:44:03Z"
},
{
"tag": "v0.17.2",
"kind": "patch",
"published_at": "2026-07-19T22:40:24Z"
},
{
"tag": "v0.17.1",
"kind": "patch",
"published_at": "2026-04-14T06:46:23Z"
},
{
"tag": "v0.17.0",
"kind": "minor",
"published_at": "2026-04-13T18:52:31Z"
},
{
"tag": "v0.16.1",
"kind": "patch",
"published_at": "2026-04-13T16:34:10Z"
},
{
"tag": "v0.16.0",
"kind": "minor",
"published_at": "2026-04-13T09:31:01Z"
},
{
"tag": "v0.15.1",
"kind": "patch",
"published_at": "2026-04-13T09:17:34Z"
},
{
"tag": "v0.15.0",
"kind": "minor",
"published_at": "2026-04-13T09:08:05Z"
},
{
"tag": "v0.14.2",
"kind": "patch",
"published_at": "2026-04-13T08:51:37Z"
},
{
"tag": "v0.14.1",
"kind": "patch",
"published_at": "2026-04-13T08:40:03Z"
},
{
"tag": "v0.14.0",
"kind": "minor",
"published_at": "2026-04-12T19:08:39Z"
},
{
"tag": "v0.13.7",
"kind": "patch",
"published_at": "2026-04-12T02:13:16Z"
},
{
"tag": "v0.13.6",
"kind": "patch",
"published_at": "2026-04-12T02:10:13Z"
},
{
"tag": "v0.13.5",
"kind": "patch",
"published_at": "2026-04-12T01:14:22Z"
},
{
"tag": "v0.13.4",
"kind": "patch",
"published_at": "2026-04-12T01:10:50Z"
},
{
"tag": "v0.13.3",
"kind": "patch",
"published_at": "2026-04-12T00:46:52Z"
},
{
"tag": "v0.13.2",
"kind": "patch",
"published_at": "2026-04-12T00:30:52Z"
},
{
"tag": "v0.13.1",
"kind": "patch",
"published_at": "2026-04-12T00:25:43Z"
},
{
"tag": "v0.13.0",
"kind": "minor",
"published_at": "2026-04-12T00:19:44Z"
},
{
"tag": "v0.12.2",
"kind": "patch",
"published_at": "2026-03-25T16:49:20Z"
},
{
"tag": "v0.12.0",
"kind": "minor",
"published_at": "2026-03-13T02:52:31Z"
},
{
"tag": "v0.9.0",
"kind": "minor",
"published_at": "2026-02-16T23:09:44Z"
},
{
"tag": "v0.8.1",
"kind": "patch",
"published_at": "2026-01-31T22:21:51Z"
},
{
"tag": "v0.8.0",
"kind": "minor",
"published_at": "2026-01-31T22:13:56Z"
},
{
"tag": "v0.7.0",
"kind": "minor",
"published_at": "2026-01-31T19:02:00Z"
},
{
"tag": "v0.6.3",
"kind": "patch",
"published_at": "2026-01-28T03:57:53Z"
},
{
"tag": "v0.6.2",
"kind": "patch",
"published_at": "2026-01-08T04:55:00Z"
},
{
"tag": "v0.6.1",
"kind": "patch",
"published_at": "2026-01-08T04:42:34Z"
},
{
"tag": "v0.5.2",
"kind": "patch",
"published_at": "2026-01-03T02:29:19Z"
},
{
"tag": "v0.5.1",
"kind": "patch",
"published_at": "2026-01-03T02:18:42Z"
},
{
"tag": "v0.5.0",
"kind": "minor",
"published_at": "2026-01-03T01:25:11Z"
},
{
"tag": "v0.4.0",
"kind": "minor",
"published_at": "2025-12-28T00:25:09Z"
},
{
"tag": "v0.3.5",
"kind": "patch",
"published_at": "2025-12-28T00:00:56Z"
},
{
"tag": "v0.3.4",
"kind": "patch",
"published_at": "2025-12-26T03:59:00Z"
},
{
"tag": "v0.3.3",
"kind": "patch",
"published_at": "2025-12-26T03:36:28Z"
},
{
"tag": "v0.3.2",
"kind": "patch",
"published_at": "2025-12-26T01:44:01Z"
},
{
"tag": "v0.3.1",
"kind": "patch",
"published_at": "2025-12-26T01:38:12Z"
},
{
"tag": "v0.3.0",
"kind": "minor",
"published_at": "2025-12-26T01:37:42Z"
},
{
"tag": "v0.2.11",
"kind": "patch",
"published_at": "2025-12-07T00:16:07Z"
},
{
"tag": "v0.2.10",
"kind": "patch",
"published_at": "2025-12-06T05:29:33Z"
},
{
"tag": "v0.2.9",
"kind": "patch",
"published_at": "2025-12-06T03:58:10Z"
},
{
"tag": "v0.2.8",
"kind": "patch",
"published_at": "2025-12-05T05:25:22Z"
},
{
"tag": "v0.2.6",
"kind": "patch",
"published_at": "2025-12-05T05:21:11Z"
},
{
"tag": "v0.2.5",
"kind": "patch",
"published_at": "2025-12-05T05:20:36Z"
},
{
"tag": "v0.2.4",
"kind": "patch",
"published_at": "2025-12-05T05:17:57Z"
},
{
"tag": "v0.2.2",
"kind": "patch",
"published_at": "2025-12-05T05:13:57Z"
},
{
"tag": "v0.2.1",
"kind": "patch",
"published_at": "2025-12-05T05:02:57Z"
},
{
"tag": "v0.0.12",
"kind": "patch",
"published_at": "2021-04-16T19:50:48Z"
},
{
"tag": "v0.0.11",
"kind": "patch",
"published_at": "2020-10-09T21:40:26Z"
},
{
"tag": "v0.0.10",
"kind": "patch",
"published_at": "2020-05-27T17:21:22Z"
},
{
"tag": "v0.0.8",
"kind": "patch",
"published_at": "2020-03-25T15:13:56Z"
},
{
"tag": "0.0.8",
"kind": "patch",
"published_at": "2020-03-18T01:18:43Z"
},
{
"tag": "0.0.7",
"kind": "patch",
"published_at": "2020-03-03T20:35:25Z"
},
{
"tag": "0.0.6",
"kind": "patch",
"published_at": "2020-03-03T19:09:45Z"
},
{
"tag": "0.0.5",
"kind": "patch",
"published_at": "2020-01-16T04:07:55Z"
},
{
"tag": "0.0.4",
"kind": "patch",
"published_at": "2020-01-15T22:08:17Z"
},
{
"tag": "0.0.3",
"kind": "patch",
"published_at": "2020-01-15T22:06:06Z"
}
],
"recent_commits": [
{
"oid": "ba27e29688043cdf2adc08f8ea470c82837c2c1c",
"body": null,
"is_bot": false,
"headline": "chore: minor readme edit",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-07-19T22:41:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ff19e47cd4374cf5829c041aaa7aa84c3619c887",
"body": null,
"is_bot": false,
"headline": "chore: document release",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-07-19T22:37:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "bf590cff8f0a5fb5d8ff38038301406f57fd7e93",
"body": null,
"is_bot": false,
"headline": "chore: clean up AGENTS.md",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-07-13T17:56:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5a4123fd9e7b40e14094b44d711eb7c618e21ab6",
"body": "…ned flows\n\nAn abandoned OIDC browser flow (browser closed without completing) held\nthe auth mutex for the plugin's full 5-minute timeout, silently blocking\nevery subsequent ssh session behind it.\n\n* Coalesce concurrent Auth.Run calls into a shared flight: joiners get\n the pending user output (auth\n[…]\nnt matches can actually share the flight\n* Always emit the auth URL on fd 4 from the OIDC plugin so joining\n sessions see where to authenticate\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: share in-flight auth attempt across ssh sessions and kill abando…",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-07-13T17:39:04Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5f6581470eb7f8ce36b7ad996bc3dd2ebf244720",
"body": null,
"is_bot": false,
"headline": "several security related tasks",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-06-23T18:33:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "80051ac7057c08573aa89c0be5848ee10cab4844",
"body": "Remove sections that restate default Claude/Go behavior (communication\nstyle, debugging philosophy, documentation conventions, camelCase). Remove\nstale maxStateSizeBytes constant reference. Delete stale worktree CLAUDE.md.",
"is_bot": false,
"headline": "chore: trim AGENTS.md to remove generic guidance",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-18T01:09:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8bcb0d82b7e3fd9f77792e56d989da69d0012aa1",
"body": "…tExpiration\n\nUse key/value format for CA endpoint status in inspect output to match\nthe style of other sections (agents, certificates).\n\nRemove unused DefaultExpiration field from discovery responses — it was\nplumbed through policy server and CA but never consumed.",
"is_bot": false,
"headline": "fix: clean up inspect CA endpoint display and remove vestigial Defaul…",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-14T06:41:42Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "404b6951ec1bd4f3b53e4259a9c281cd2ebf5fb2",
"body": "When all circuit breakers are open, bypass them and try entries directly\ninstead of returning AllUnavailableError immediately. This fixes the case\nwhere a transient outage (e.g., no network) trips all breakers, locking\nout all CAs for the full 10-minute cooldown even after recovery.\n\nAlso expose per-CA-endpoint circuit breaker state (healthy/broken) in\n`epithet agent inspect` output, both human-readable and JSON.",
"is_bot": false,
"headline": "feat: add breakerpool all-down fallback and expose CA status in inspect",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-13T18:44:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8c5f250ae6e76669437b21fc784ad4a6c0d11800",
"body": "When the auth token expires, getDiscoveryPatterns would call Hello with\nthe stale token, get a 401, and treat it as a terminal error. This\ncaused match to fail at the discovery step without ever attempting cert\nrenewal. Handle InvalidTokenError from Hello the same way the cert\nrequest loop does: clear the token, re-run auth, and retry.",
"is_bot": false,
"headline": "fix: re-authenticate on 401 during discovery Hello",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-13T16:29:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3227d08c8e9e6b04ca892954fb66571c1a62249d",
"body": "The cert fingerprint matches what 'epithet agent inspect' displays,\nenabling direct correlation. The connection hash (%C) is not meaningful\non the CA side so it is removed from the log output.",
"is_bot": false,
"headline": "feat: add cert fingerprint to issuance log, remove connection hash",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-13T09:28:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cb2fcf34182418fa0254ff1f8fdc2b5a957d6d23",
"body": "Enables correlating inspect output with CA issuance logs, which log\nthe serial as the primary certificate identifier.",
"is_bot": false,
"headline": "feat: show certificate serial number in agent inspect output",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-13T09:25:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b9e0ab4f764e2d0f41fb3b072805d633e1eddb83",
"body": "The cert audit logger used slog.Info but the default log level is Warn,\nso certificate issuance events were silently dropped unless -v was passed.\nWrap the handler to force Info-level minimum for audit logging.",
"is_bot": false,
"headline": "fix: always log certificate issuance regardless of verbosity level",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-13T09:14:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1112d5634644b54b7667f537bbe23ccc1b1c7401",
"body": "Previously only GetCert used the breakerpool for priority-based failover\nand circuit breaking. Hello and GetPublicKey iterated endpoints in\ninsertion order, ignoring priority, and had no circuit breaker support.\n\nChange the pool type from Pool[*CertResponse, string] to Pool[any, string]\nso all three methods share the same pool. This gives Hello and GetPublicKey\nproper priority ordering, round-robin within tiers, and shared circuit\nbreaker state across all request types.",
"is_bot": false,
"headline": "fix: route Hello and GetPublicKey through breakerpool",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-13T09:05:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4377bfecda0ef87cf6bf4a04a1cec97c5182f569",
"body": null,
"is_bot": false,
"headline": "chore: switch to formula from cask",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-13T08:48:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a12d2c2a0ddb499a60f8cacc642a3ca9f5dfe966",
"body": null,
"is_bot": false,
"headline": "move homebrew formula back to ci",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-13T08:37:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e7e3f5bd16243e970641117883424e0505cd8873",
"body": "Replace the old rekor-based Bearer signature scheme with RFC 9421 HTTP\nMessage Signatures for CA-to-policy-server authentication. The CA now\nowns the /discovery endpoint and proxies to the policy server, removing\nthe broken Link header relay that failed behind reverse proxies.\n\nKey changes:\n- New pk\n[…]\n config public, match patterns\n require valid Bearer token validated via policy server hello)\n- Combined mode simplified: no reverse proxy mux, CA listens directly\n- Removed sigstore/rekor dependency",
"is_bot": false,
"headline": "feat: implement RFC 9421 discovery protocol and CA-to-policy auth",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T18:54:25Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5018758c3653ab2c76cc9a5ccd48e8f4019b9bbb",
"body": null,
"is_bot": false,
"headline": "a plan to clean up bootstrapping",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T05:11:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2d24db78b58fe545b0826df6e9ee101c817d4437",
"body": "The CA was deriving the discovery URL from the internal policy socket\npath (unix:///tmp/.../policy.sock/discovery) which is meaningless to\nexternal clients. Fall back to /discovery (relative) instead, which\nthe client resolves against the CA URL it's already talking to.",
"is_bot": false,
"headline": "fix: use relative discovery URL in CA pubkey response",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T02:19:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "761491f5019929e9fd0857c05ff176618dddea17",
"body": "Remove explicit procname so rc.subr defaults to command (/usr/sbin/daemon),\nmatching the supervisor PID stored by -P. Fixes status reporting and\nclean shutdown.",
"is_bot": false,
"headline": "fix: align rc.d procname with daemon -P pidfile",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T02:10:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4ef52636b239380b091334539be34be983cfa6e7",
"body": "parseLinkHeader now resolves relative URLs against the request's\nbase URL. Previously /discovery resolved to http://localhost/discovery\nwhich broke clients behind a reverse proxy. The server can now use\nrelative Link headers and the client resolves them correctly.\n\nAlso fix sample config to use client-id instead of audience, create\nlog file in pre-install script so the epithet user can write to it.",
"is_bot": false,
"headline": "fix: resolve relative discovery URLs in Link header",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T02:07:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c90607bc4cce992bad1ce1358f48823aa4e3d73b",
"body": "rc.subr interprets ${name}_user as a magic variable and runs the\nentire command as that user before daemon(8) gets invoked. This\ncaused daemon to fail writing the pidfile to /var/run/. Rename to\nepithet_server_runas so daemon starts as root, writes the pidfile,\nthen drops to the epithet user via -u.",
"is_bot": false,
"headline": "fix: rename rc.conf user variable to avoid rc.subr conflict",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T01:24:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "811de25ff503e3d4f3747623ef07429aa084ff8b",
"body": "Remove ca-key and listen tunables from rc.d script and add them to\nthe sample YAML config instead. The rc.d script now only handles\nprocess management (config path, user, logfile). Server behavior\nis configured in one place.",
"is_bot": false,
"headline": "refactor: move server settings from rc.conf to config file",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T01:11:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b791361180c59b93c0bb1d87e36b72a24543a5ee",
"body": "Plain HTTP should not be exposed to the network. Default to\n127.0.0.1:8080 so a TLS-terminating reverse proxy is required\nfor external access.",
"is_bot": false,
"headline": "fix: default listen address to localhost only",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T01:10:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "491529989793617010e02e948984b5c5674f9269",
"body": "daemon(8) -p writes the pidfile as the -u user, which can't write\nto /var/run/. Switch to -P which writes the supervisor pidfile as\nroot before dropping privileges.",
"is_bot": false,
"headline": "fix: use daemon -P for pidfile to avoid permission denied",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T01:08:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "03e52275231434e6e9c4b8e13e0a2be058f1df25",
"body": "Add pre-install script to +MANIFEST that creates the epithet user\nvia pw(8) if it doesn't already exist. Tested on FreeBSD 15.0.",
"is_bot": false,
"headline": "feat: create epithet service user automatically on pkg install",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T00:44:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "77d6bb85492978ec39a99f31bdcd3f006353c7f0",
"body": "pkg(8) stamps the ABI from the build host OS, so building in a\nFreeBSD 14 VM produced packages that FreeBSD 15 rejected. Add an\nABI variable (default FreeBSD:15:amd64) to the Makefile and\nsubstitute it into the manifest template. The binary is statically\nlinked so the ABI is purely metadata.",
"is_bot": false,
"headline": "fix: set explicit ABI in FreeBSD package manifest",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T00:27:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4ed51351a1c80b077a7c7353f7524a536cd1e89d",
"body": "checkout v4→v6, setup-go v5→v6, goreleaser-action v6→v7.\nNode.js 20 actions are deprecated and will stop working Sep 2026.",
"is_bot": false,
"headline": "chore: bump GitHub Actions to Node.js 24 versions",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T00:22:42Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "088700b7a5c5562b1491e12522d54d73593b0193",
"body": "Add release.yml workflow triggered on v* tag push that runs goreleaser\nand builds a FreeBSD .pkg via vmactions/freebsd-vm. Tests run before\nrelease to prevent publishing broken artifacts.\n\nSimplify local make release to only create the tag, with CI handling\nthe actual build and publish. Modernize build.yml action versions and\nskip tag pushes to avoid duplicate runs.",
"is_bot": false,
"headline": "feat: move release builds to GitHub Actions CI",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T00:15:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "816b21ade14070fa74cbc471718906766c75baef",
"body": "Add contrib/freebsd/ with Makefile, +MANIFEST, rc.d service script,\nsample config, and plist for building FreeBSD packages via pkg create.\nTested on FreeBSD 15.0-RELEASE/amd64.",
"is_bot": false,
"headline": "feat: add FreeBSD pkg packaging to contrib/",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-12T00:04:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1ac41b6400406f096a851c68b484612255b018ff",
"body": "Fix issues found by Codex code review:\n- Use oidc.client_id instead of oidc.audience in policy server docs\n- Use defaults.expiration instead of default_expiration\n- Point Google Workspace prereqs to policy server guide instead of quick-start",
"is_bot": false,
"headline": "docs: fix incorrect config field names and broken links",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-11T00:08:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ff7970579229971efa3337782cf1cb64940bd5b9",
"body": "Remove cuelang.org/go, kongcue, and ~10 transitive CUE dependencies\n(OCI registry, protobuf parser, arbitrary-precision math). Replace with\nkong-yaml for CLI config resolution and direct yaml.v3/json unmarshaling\nfor policy data.\n\nTwo clean config paths replace the single CUE-unified approach:\n- Sca\n[…]\ny from YAML via\n config.LoadSection()\n\nConfig keys now use kebab-case to match CLI flag names (ca-pubkey not\nca_pubkey). The applyOverrides methods are removed since Kong handles\nprecedence natively.",
"is_bot": false,
"headline": "refactor: replace CUE config with kong-yaml and direct YAML parsing",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-10T23:27:36Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ce728049d9e7916f249062c14a15b15a37213cb5",
"body": null,
"is_bot": false,
"headline": "chore: update dependencies",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-04-07T20:05:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c197b4036cd570c5b6e02f2f0324f8fcc905e822",
"body": "Replace the two-tier content-addressed discovery system (redirect at\n/d/current to immutable /d/{hash} URLs) with a single /discovery\nendpoint that serves content directly using Vary: Authorization for\nHTTP cache discrimination.\n\n- Remove content-addressed hash computation (ComputeUnauthDiscoveryHas\n[…]\nand all hash-based routing\n- Replace DiscoveryHash config field with DiscoveryEnabled bool\n- Rename endpoint from /d/current to /discovery\n- Client caching still works via RFC 7234 Vary header support",
"is_bot": false,
"headline": "refactor: simplify discovery to single /discovery endpoint",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-03-27T02:23:13Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "781e278a9db514f507c590fa77f406004f06e2ce",
"body": null,
"is_bot": false,
"headline": "chore:update docs",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-03-13T04:22:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5e2e6df316fe8b5c8d6c0af3864fa18232d02217",
"body": "Delete stale docs (alternatives.md, ideas/bastion.md, development-tools.md,\npolicy-config-design.md). Simplify README by removing inaccurate sections\n(wrong config format, nonexistent --match/--broker flags) and moving detail\nto docs/. Fix --match flag references across oidc-setup.md and\nauthentication.md. Fix commands table (add server, fix inspect).",
"is_bot": false,
"headline": "docs: audit and simplify documentation",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-03-13T03:05:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f35ba5008e6e1a6602270d8960d4bfb70e63938a",
"body": null,
"is_bot": false,
"headline": "still fighting the makefile",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-03-13T02:51:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0609ff574065c6e8c83b4fbbf344691808b25582",
"body": null,
"is_bot": false,
"headline": "chore:clean up release machinery",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-03-13T02:49:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5aea1b22054d44395ec1a612923bd4d0054f0c29",
"body": null,
"is_bot": false,
"headline": "chore:svu includes the v",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-03-13T02:48:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9cf01837a859d016ff6043edd9fe9aa711d83cd4",
"body": null,
"is_bot": false,
"headline": "chore:clean up release machinery",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-03-13T02:46:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4c03cd41ec14168c43251d72313223493c32fcd8",
"body": null,
"is_bot": false,
"headline": "task for a frebsd pkg",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-03-09T03:10:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a4028d810a7b4e2aba9f9255b7c974ab86a1f4a5",
"body": "Use a local httptest server serving openid-configuration and empty JWKS\ninstead of hitting accounts.google.com. Tests no longer need network\naccess or -short skip guards.",
"is_bot": false,
"headline": "test: replace real OIDC provider with mock in unit tests",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-02-21T22:54:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a1e2b45ec18f066ff39037dec307fc8a9d10acad",
"body": "… subprocesses\n\nAdds a combined server command that starts CA and policy as subprocesses\nbehind a single reverse proxy, simplifying deployment to a single process\nand port. The proxy routes /d/* to the policy server and everything else\nto the CA.\n\nKey changes:\n- cmd/epithet/server.go: supervisor tha\n[…]\nre flag\n- test/server/server_test.go: integration test with mock OIDC server\n verifying proxy routing, discovery redirects, and clean shutdown\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: add `epithet server` command to run CA and policy as supervised…",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-02-21T22:50:16Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "37d33014e1c7db0ea52295155a109bb619d4dcfd",
"body": "Merge the bootstrap (unauthenticated auth config) and discovery\n(authenticated match patterns) flows into a single /d/current endpoint\nthat routes by Authorization header presence:\n\n- Unauthenticated: returns Discovery{Auth: ...}\n- Authenticated: returns Discovery{Auth: ..., MatchPatterns: [...]}\n\nR\n[…]\ne BootstrapHash()/DiscoveryHash()\nmethods with standalone ComputeUnauthDiscoveryHash() and\nComputeAuthDiscoveryHash() functions. The redirect handler sets\nVary: Authorization for correct HTTP caching.",
"is_bot": false,
"headline": "refactor: unify bootstrap and discovery into single auth-aware endpoint",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-02-16T23:08:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b6f62360c03caad7dac1840b8a6909e3468ff905",
"body": "getDiscoveryPatterns was calling auth.Run with nil userOutput,\ndiscarding fd 4 output during the initial auth triggered by\nshouldHandle. Add e2e gRPC streaming test that caught this.",
"is_bot": false,
"headline": "fix: thread userOutput through discovery auth path",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-02-16T22:34:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b9f73c406c9e6b112e79f3addccdeab17c589c60",
"body": null,
"is_bot": false,
"headline": "chore: cleaning up agent instructions",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-02-15T02:13:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d557e76ee2d5017598fc46b7a591a9987b5497de",
"body": "Plan to detect remote SSH sessions (via SSH_CLIENT/SSH_CONNECTION env vars)\nand use Device Authorization Grant (RFC 8628) instead of browser-based auth\nwhen users are SSH'd in. Also includes doc improvements for policy server\nconfiguration modes (inline vs dynamic policy source).",
"is_bot": false,
"headline": "Add yatl task for SSH session detection in OIDC auth",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-02-01T04:17:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "aba4747e5c62300a31dc7696b66960115883fb8b",
"body": "- rekor v1.4.3 → v1.5.0 (fixes SSRF and nil pointer deref)\n- sigstore v1.10.3 → v1.10.4 (fixes TUF path traversal)\n\nResolves Dependabot alerts #43, #44, #45.",
"is_bot": false,
"headline": "fix: upgrade sigstore packages to fix security vulnerabilities",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-31T22:07:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "dd70cf17bf7484b0eb3f1f3e56df69126d1aaa40",
"body": "Separate policy data (users, hosts, defaults) from server config,\nallowing policy to be loaded from a URL per-request. This enables\npolicy updates without redeploying the server.\n\n- Add PolicyLoader with support for CUE, YAML, JSON formats\n- Add PolicyProvider interface for static and dynamic policy\n[…]\n:// URL)\n- HTTP caching via httpcache respecting Cache-Control headers\n- File caching via mtime to avoid re-parsing unchanged files\n- Backwards compatible: inline config still works when no source set",
"is_bot": false,
"headline": "feat: add dynamic policy loading via --policy-source",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-31T22:06:02Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3a0f016560fa367c6806c1c80e0e9c2596173dac",
"body": "- Merge Run() and RunWithStderr() into single Run(attrs, userOutput) method\n- Change stderr callback to io.Writer for simpler, standard interface\n- Add fd 4 for user-visible progress output (e.g., OIDC device codes)\n- Keep stderr (fd 2) solely for error messages included in failures\n- Rename MatchWi\n[…]\nerr field to user_output\n\nAuth command protocol is now:\n- fd 1 (stdout): token\n- fd 2 (stderr): errors (captured for error messages)\n- fd 3: state blob\n- fd 4: user-visible progress (streamed to user)",
"is_bot": false,
"headline": "refactor: simplify auth command interface and add fd 4 for user output",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-31T19:01:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f3247de7d400f01b48d602973c23084efaa8cc6c",
"body": "Replace the broker's internal RPC mechanism with gRPC to enable:\n- Server streaming for auth plugin stderr (visible to user during OIDC flows)\n- Cross-platform client generation (Swift/macOS, C#/.NET)\n\nKey changes:\n- Add proto/brokerv1/broker.proto with streaming Match and unary Inspect RPCs\n- Add b\n[…]\nupport stderr streaming callback\n- Add Broker.MatchWithStderr() as the core implementation\n- Update match.go and inspect.go CLI commands to use gRPC client\n- Update all broker tests to use gRPC client",
"is_bot": false,
"headline": "feat: migrate broker RPC from net/rpc+GOB to gRPC",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-28T16:59:49Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "19ee6211a63016ff2b0a132ee9c1221e43b62fba",
"body": "Non-matching hosts are not errors - they just mean epithet doesn't\nhandle this connection. The match command now exits with code 1\nsilently, letting SSH fall through to normal authentication.",
"is_bot": false,
"headline": "fix: exit silently when host doesn't match discovery patterns",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-28T15:45:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d4912b924aa351a262528e32edb2d7378794c93a",
"body": "Remove informational messages that printed to stderr during successful\nOIDC authentication. This was confusing when match failed because a host\ndidn't match discovery patterns - users would see auth messages only to\nlearn the connection wasn't handled by epithet.\n\nKeep error messages (browser failed to open) since those require user action.",
"is_bot": false,
"headline": "fix: remove verbose OIDC login output during match",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-28T15:39:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "817bf446dec3d2c74ba54a03a814bc12f6ffc7d0",
"body": "Remove unnecessary options (PubkeyAuthentication, PasswordAuthentication,\nKbdInteractiveAuthentication, GSSAPIAuthentication, PreferredAuthentications,\nIdentityFile) from the generated SSH config block. This allows natural\nfallback to ~/.ssh/id_* keys and password auth when epithet certificates\naren't available, which is important for production failure recovery.",
"is_bot": false,
"headline": "fix: simplify generated SSH config to just IdentityAgent",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-28T15:37:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d63e0a915d12cef2b3238aeecabd89c37eaeaff2",
"body": "Move architecture documentation to docs/architecture.md (~310 lines) and\nkeep only Claude-specific guidance in CLAUDE.md (~170 lines, down from 461).\n\nThis separation provides:\n- Smaller context for Claude sessions (most tasks only need behavior guidance)\n- Human-readable architecture docs for all developers\n- Single canonical location for architecture changes",
"is_bot": false,
"headline": "docs: split CLAUDE.md into focused modules",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-28T15:11:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8d1334710bd03daa92bfe4a3665fbcc614b07755",
"body": "Reduce CLAUDE.md from 862 to 461 lines (~46% reduction) by:\n- Replace auth protocol examples with reference to docs/authentication.md\n- Replace policy server protocol details with reference to docs/policy-server.md\n- Condense Broker → CA protocol section\n- Remove redundant SSH config examples (reference examples/ dir)\n- Replace detailed implementation checklist with brief status summary\n- Remove duplicate \"Integration with OpenSSH\" section",
"is_bot": false,
"headline": "docs: shrink CLAUDE.md by replacing duplicated content with references",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-28T14:56:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "171340e3608aa10b740599df32a15d7c2703637a",
"body": null,
"is_bot": false,
"headline": "docs: add releases section pointing to packaging repo",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-08T05:05:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7b572ce62d0f95fc6986841a84c1b9f95f93b55d",
"body": null,
"is_bot": false,
"headline": "chore: remove CI release workflow (using local releases)",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-08T05:00:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "334ef883f3dd8701c600945cb36ff680e31b4782",
"body": null,
"is_bot": false,
"headline": "fix: add missing period to expandPath comment",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-08T04:53:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "da43ff0d82127340d349dbc0ae355ac2e8de799b",
"body": null,
"is_bot": false,
"headline": "working on release machienry",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-08T04:41:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1e38cc54531dbb88fa0522d5e2c0200ce2de585f",
"body": "The cgo requirement made this incompatible with cross-compiled\nCI releases. Will revisit with a different approach later.",
"is_bot": false,
"headline": "Revert --native-log flag for Apple Unified Logging",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-05T21:19:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b91454a362bf1a047f5ebcbb2e10993e62bfb904",
"body": "Add macOS-specific slog.Handler that writes to os_log via cgo,\nenabling logs to appear in Console.app with subsystem dev.epithet.\n\nOn non-Darwin platforms, the flag falls back to console logging\nwith a warning.",
"is_bot": false,
"headline": "Add --native-log flag for Apple Unified Logging support",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-05T21:08:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a747f61dff584071bcfc17607004e49bee26238f",
"body": "Allow the policy server to accept an OIDC client secret via CLI flag\n(--oidc-client-secret) or config file (policy.oidc.client_secret).\nThe secret is included in the bootstrap response so clients can use it\nfor authentication with confidential OIDC clients.",
"is_bot": false,
"headline": "Add OIDC client secret support to policy server",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-03T02:26:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "18f077337d0604834a9a9410b77a65947e2752ee",
"body": "The CA now extracts the bootstrap URL from the policy server's Link header\ninstead of deriving it from the policy URL. This allows the policy server\nto control the exact URL for CDN caching scenarios.\n\nChanges:\n- Rename extractDiscoveryURL to extractLinkURLs to parse multiple link values\n- Extract a\n[…]\nserver uses cached bootstrap URL with fallback to derived URL\n- Policy server includes both discovery and bootstrap in Link headers\n- Make --auth optional on epithet agent (discover from CA bootstrap)",
"is_bot": false,
"headline": "Learn bootstrap URL from policy server Link header",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-03T02:15:23Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a60ce7d225e93756a18f4744a6de095aa535df2d",
"body": "Implement content-addressable discovery URLs with two tiers:\n- Bootstrap (/d/bootstrap → /d/<hash>): no auth, returns OIDC config\n- Discovery (/d/current → /d/<hash>): requires auth, returns match patterns\n\nChanges:\n- Rename OIDCConfig.Audience to ClientID (breaking config change)\n- Add BootstrapAut\n[…]\n- Add GetPublicKey/GetBootstrap to caclient for bootstrap flow\n- Add AuthConfigToCommand to convert bootstrap config to auth command\n\nIncludes comprehensive unit tests and end-to-end integration test.",
"is_bot": false,
"headline": "Add two-tier discovery: public bootstrap and authenticated endpoints",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2026-01-03T01:20:55Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0a35fd5c5e0fedc31bbebf05f4cb379aaf612fce",
"body": null,
"is_bot": false,
"headline": "",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-28T00:21:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "69951f562da0edfcf817c444905199acbf5cb62d",
"body": "Enables serving discovery URLs through a CDN by allowing the policy server\nto return absolute URLs instead of relative ones. When set, both the Link\nheader and redirect Location use the configured base URL.",
"is_bot": false,
"headline": "Add --discovery-base-url flag to policy server",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-28T00:21:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ed83619639d8e00ea505b36a414451527eb4f727",
"body": null,
"is_bot": false,
"headline": "",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-27T19:50:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3cdad5887aac4237ceac25c17064d5ff6b624d30",
"body": "Introduce /d/current endpoint that redirects (302) to the content-addressed\n/d/{hash} endpoint. This enables proper HTTP cache invalidation:\n\n- /d/current: cached 5 minutes, temporary redirect to content-addressed URL\n- /d/{hash}: cached forever (immutable)\n\nUses 302 Found (temporary) rather than 30\n[…]\n new discovery\nURL after their cached redirect expires. The CA/policy server Link header\nnow always points to /d/current.\n\nIncludes test verifying caclient follows redirects with Authorization header.",
"is_bot": false,
"headline": "Add discovery URL redirect pattern for HTTP caching",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-27T19:29:44Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a2e1937f53efdd79ca8fd631e871b8481052a7d3",
"body": "Replace time.Sleep() calls with proper synchronization using a new\nReady() channel on Broker that is closed when the listener is ready.\n\nChanges:\n- Add ready channel to Broker struct, closed after listener starts\n- Add Ready() method returning the channel for callers to wait on\n- Replace all time.Sl\n[…]\nfor concurrent execution\n- Add shortTempDir() helper to avoid Unix socket path length limits\n (macOS has ~104 byte limit, t.TempDir() paths can exceed this)\n\nTests now complete in ~2.4s consistently.",
"is_bot": false,
"headline": "Remove arbitrary time.Sleep waits from broker tests",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-27T18:48:52Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "901c1bb434b644868400bf5951db9faacb0d1a7d",
"body": null,
"is_bot": false,
"headline": "Cleaning up tasks",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-27T00:52:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2c99173bd84ee5eacf65e481ef9530a02252d767",
"body": "The broker base64url-encodes tokens for binary safety, but the discovery\nhandler was passing the encoded token directly to the OIDC validator.\nThis caused \"malformed jwt\" errors since the validator expected a raw JWT.\n\nAdd base64url decoding in discovery handler to match the policy handler\nbehavior. Update tests to use properly encoded tokens.",
"is_bot": false,
"headline": "Fix discovery handler to decode base64url tokens",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-26T03:55:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4849e06decdc3635c9f4273e2894b96a2867f5fb",
"body": "Verifies that patterns like badb{,.home} correctly match both\nshort hostnames (badb) and FQDNs (badb.home).",
"is_bot": false,
"headline": "Add test for brace expansion pattern matching",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-26T03:28:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2a41f5a6af03150b7fe6d52488e46f88a238c65b",
"body": null,
"is_bot": false,
"headline": "cleanup deps",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-26T03:26:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1a0e659a68c93cf41c4405a2397e6896e7565ee1",
"body": "Replace filepath.Match with doublestar.Match in all host pattern matching\nlocations to enable brace expansion syntax like `badb{,.home}` for matching\nboth short hostnames and FQDNs with a single pattern.\n\nAffected files:\n- pkg/policy/policy.go\n- pkg/policyserver/evaluator/evaluator.go \n- pkg/broker/broker.go",
"is_bot": false,
"headline": "Switch host pattern matching to doublestar for brace expansion",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-26T03:24:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f62ab78b8d24023d777059d99ffd81e93bba003c",
"body": "Previously, defaults.Allow created a wildcard '*' pattern that matched\nany host. This meant users could get certificates for hosts not explicitly\nlisted in the Hosts config.\n\nNow, a host must match an explicit pattern in Hosts before authorization\nis granted. defaults.Allow is merged into each host \n[…]\n- Expiration/extensions use pattern matching (not exact key lookup)\n\nExample: With hosts: {\"v*\": {...}, \"badb\": {}} and defaults.allow,\nconnecting to 'wobble' now fails, while 'v1' and 'badb' succeed.",
"is_bot": false,
"headline": "Policy server: require host pattern match before defaults apply",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-26T03:14:39Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "47df486be369810d8039dd166a0f6f86628bdb84",
"body": null,
"is_bot": false,
"headline": "reuire user match at least one host to do a HELLO",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-26T03:04:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "724a02c1a5d8359657b628db0a47b85e05322bfe",
"body": "- pkg/caclient: Add timing to doRequest, doHello, fetchDiscovery\n- pkg/ca: Add logger field and WithLogger option, log policy requests\n- cmd/epithet/ca: Wire up logger to CA\n- cmd/epithet/policy: Add logging to resolveCAPubkey URL fetches\n\nLogs method, URL, body_size, duration_ms, and status at DEBUG level.\nDoes not log sensitive data (tokens, body content).",
"is_bot": false,
"headline": "Add DEBUG level logging for all HTTP requests",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-26T02:56:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d88bf2d936e66161c03ef12abb58266f1eeea2b7",
"body": "Use #!/bin/bash instead of #!/bin/sh in the test script. On Linux,\n/bin/sh is typically dash, which doesn't support \\x hex escapes in\nprintf - it outputs them as literal characters instead of binary bytes.",
"is_bot": false,
"headline": "Fix TestAuth_Run_BinaryTokenPreservation on Linux CI",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-26T01:40:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6ecb0617824279037c5f4ee19ec8fde5227e9fb5",
"body": null,
"is_bot": false,
"headline": "discovery end to end I think",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-26T01:35:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f7cca30706a8dce135e0ade860b34f0b1f4c2601",
"body": "GetDiscovery() now uses a cached discovery URL instead of making hello\nrequests to the CA. The URL is learned from cert response Link headers\nand cached in the Client struct.\n\nThis avoids unnecessary network calls when checking host patterns in\nshouldHandle() - if no discovery URL is cached yet, it \n[…]\nached URL instead of making hello requests\n- GetCert() caches the discovery URL from Link header\n- Add SetDiscoveryURL() for testing\n- Remove unused doHelloRequest()\n- Update caclient and broker tests",
"is_bot": false,
"headline": "caclient: Cache discovery URL to short-circuit pattern checks",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-25T03:38:59Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c65455b9e4ef798ab72690e7e5d3abe49ca5f3a3",
"body": "Add GET /d/<hash> discovery endpoint that returns match patterns with\nCache-Control: immutable header for HTTP caching.\n\nRefactor to separate authentication from authorization:\n- Add TokenValidator interface for token validation (extracts identity)\n- Change PolicyEvaluator.Evaluate to take identity \n[…]\nscovery endpoint\n- pkg/policyserver/policyserver.go: Add TokenValidator interface\n- pkg/policyserver/oidc/validator.go: Implement ValidateAndExtractIdentity\n- cmd/epithet/policy.go: Wire up /d/* route",
"is_bot": false,
"headline": "Policy server: Add discovery endpoint and separate auth from authz",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-24T23:47:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "58862c77e57c0f650d4110e56ff6584420b94f6c",
"body": null,
"is_bot": false,
"headline": "WIP on discovery handling",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-24T23:27:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0ad8c231f2d20b909a711ba01f7b3f23d346d208",
"body": "- Add Discovery type with MatchPatterns\n- Add CertResponse type wrapping certificate, policy, and discovery URL\n- Add parseLinkHeader() internal function for RFC 8288 Link header parsing\n- Update GetCert to return CertResponse with discovery URL\n- Replace Hello with GetDiscovery that validates token and fetches discovery\n- Update broker to use CertResponse\n- Add tests for GetDiscovery and GetCert with discovery URL",
"is_bot": false,
"headline": "CA client: Link header parsing and GetDiscovery",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-24T23:07:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c4f3ba02be52a99b2c24e75cb538b6b461e0aa8b",
"body": null,
"is_bot": false,
"headline": "bt -> yatl",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-24T04:33:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e8f0ee469c106e2a7ab4a1fc38d9b20cb622bd61",
"body": "Read Link header from policy server responses, resolve relative URLs\nagainst the policy server URL using url.URL.ResolveReference (RFC 3986),\nand set the resolved Link header on CA server responses.\n\nChanges:\n- Add DiscoveryURL field to PolicyResponse and PolicyError\n- Add extractDiscoveryURL() help\n[…]\nLink headers\n- Set Link header on all CA responses (success, errors, hello)\n\nTests:\n- Unit tests for extractDiscoveryURL (relative, absolute, malformed)\n- Integration tests for Link header passthrough",
"is_bot": false,
"headline": "CA server: Pass through Link header from policy server",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-19T05:03:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b28b76e8dbd994c088fedd6f39ea25c5859d32ef",
"body": "Add Link header to all policy server responses containing a relative\ndiscovery URL: </d/hash>; rel=\"discovery\"\n\n- Add DiscoveryHash() method to PolicyRulesConfig that computes a\n content-addressable 12-char SHA256 hash of the policy rules (hosts\n and defaults.allow keys, sorted for determinism)\n- \n[…]\nh in cmd/epithet/policy.go with logging\n\nThe relative URL allows the CA to rewrite it to absolute using its\nknown policy server URL. The hash is extensible for future matching\nattributes beyond hosts.",
"is_bot": false,
"headline": "Policy server: Add Discovery Link header",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-19T04:34:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "42522109d5a591d34a72928585190e276e7cf753",
"body": null,
"is_bot": false,
"headline": "Cleanup tasks whch are done",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-18T06:09:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f89891c99c50ce93fc8c04209eeef32139eacd17",
"body": " Add Hello(ctx, token) method to validate a token with the CA server without\n requesting a certificate. Sends empty body {} with Authorization: Bearer header.\n\n - Returns nil on success (200), or appropriate error type (InvalidTokenError,\n PolicyDeniedError, CAUnavailableError, etc.)\n - Tries endpoints in priority order, fails over to next CA on 5xx errors\n - Auth/policy errors (401, 403) return immediately without failover",
"is_bot": false,
"headline": "Add Hello() method for token validation",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-18T06:06:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d6937f60a0699a01f1a4b4052b2d6d4dac0d479b",
"body": " Protocol changes for Broker→CA and CA→Policy communication:\n\n Broker→CA:\n - Token sent in Authorization: Bearer header (not request body)\n - CreateCertRequest fields are now pointers for shape-based routing\n\n CA→Policy:\n - Signature sent in Authorization: Bearer header (not request body)\n - \n[…]\nuting in CA server:\n - Empty body (both fields nil) = hello request, validates token, returns 200\n - Both fields present = certificate request (existing flow)\n - One field present = 400 Bad Request",
"is_bot": false,
"headline": "Move tokens and signatures to Authorization headers; add hello requests",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-18T05:58:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "97e40f97af8a9299534551bb1c496a1f780e62bc",
"body": null,
"is_bot": false,
"headline": "need to switch broker control socket protocol",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-15T05:22:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1522063a54e4e16bf1edd2df8cf2b73041c30d17",
"body": null,
"is_bot": false,
"headline": "clean up tasks",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-14T20:16:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "25114a46e330bcf25f9293b06c898d62cb6c04ba",
"body": null,
"is_bot": false,
"headline": "clean up task names",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-14T17:41:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a7797d9067893f7ae11b51ce614f164bc5d9decc",
"body": null,
"is_bot": false,
"headline": "more design work to get efficient match",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-14T17:37:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b9bf43336751745d885b2520ce1008e3ec48ed03",
"body": "Tokens from auth plugins may contain arbitrary bytes (invalid UTF-8).\nPreviously, raw bytes were cast to string then JSON encoded, which\ncorrupts invalid UTF-8 (replaced with U+FFFD).\n\nNow tokens are:\n- Base64url encoded immediately upon receipt from auth plugin (broker)\n- Passed through CA unchange\n[…]\nkg/broker/auth_test.go: update expected values, add binary token test\n- pkg/policyserver/policyserver.go: decode token before evaluation\n- pkg/policyserver/policyserver_test.go: encode tokens in tests",
"is_bot": false,
"headline": "Fix token encoding: base64url encode at broker, decode at policy server",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-14T17:10:15Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8d7eac1691f6c719b178cf480f8650eef95075ce",
"body": null,
"is_bot": false,
"headline": "more protocol work",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-14T16:37:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c75a17856915a996dfb256a33b6628f5223f32b3",
"body": "Added task 6v9zryht to explore mckoss/dawg packed-trie format for\nefficient host encoding when there are thousands of hosts without\nnice glob patterns. Uses ARPA-style reversed hostnames for better\nsuffix compression.\n\nBlocked on basic discovery implementation (xd0v5v9j).",
"is_bot": false,
"headline": "Discovery protocol design: Add packed trie (DAWG) exploration task",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-14T06:00:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3e7f879fc37fb0a7cc3abffa5ec4d89fe07465ac",
"body": "…hanges\n\nProtocol changes:\n- Bearer auth in Authorization header (base64url encoded tokens)\n- Single CA endpoint with shape-based routing (hello vs cert requests)\n- Policy server returns Link header with discovery URL\n- CA passes through Link header unchanged\n- Broker caches discovery, short-circuit\n[…]\nserver pass through link header\n- xh: CA client hello request\n- sd: Policy server discovery endpoint\n- ca: CA client link header parsing\n- 18: Broker discovery caching\n- xd: Broker match short-circuit",
"is_bot": false,
"headline": "Discovery protocol design: Add bt tasks for CA/broker/policy server c…",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-14T05:21:20Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "cfb60d8fef394e333e4c94698c7fcc1fdf24bb58",
"body": "When a CA/policy server cannot or is unwilling to handle a connection,\nit can now return HTTP 422. This is distinct from:\n- 401 (token invalid) - triggers retry with fresh token\n- 403 (policy denied) - authorized but not allowed\n- 422 (not handled) - this CA doesn't serve this connection\n\nThe broker\n[…]\nn policyserver\n- Add broker error handling (no retry, fail match)\n- 422 does not trip circuit breaker (not infrastructure issue)\n- Add tests for caclient, policyserver\n- Update CLAUDE.md documentation",
"is_bot": false,
"headline": "Add 422 Unprocessable Content handling for CA/policy server",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-14T04:23:36Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7e37faf1837d304bb293f44c2a9a11b5eaba8784",
"body": null,
"is_bot": false,
"headline": "task to clean up ssh block",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-14T00:02:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f409cb7f1bcdb9370a2119d7d74eba2981ed5d23",
"body": null,
"is_bot": false,
"headline": "adding metric tasks and some task cleanup",
"author_name": "Brian McCallister",
"author_login": "brianm",
"committed_at": "2025-12-11T19:14:12Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 57,
"commits_last_year": 231,
"latest_release_at": "2026-07-19T22:44:03Z",
"latest_release_tag": "v0.17.3",
"releases_from_tags": false,
"days_since_last_push": 8,
"active_weeks_last_year": 25,
"days_since_latest_release": 8,
"mean_days_between_releases": 10.8
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": false,
"health_percentage": 37,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "github.com/epithet-ssh/epithet",
"exists": true,
"license": null,
"keywords": [],
"ecosystem": "go",
"matches_repo": true,
"registry_url": "https://pkg.go.dev/github.com/epithet-ssh/epithet",
"is_deprecated": false,
"latest_version": "v0.17.3",
"repository_url": "https://github.com/epithet-ssh/epithet",
"versions_count": 69,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": null,
"latest_published_at": "2026-07-19T22:37:40Z",
"latest_version_yanked": null,
"days_since_latest_publish": 8
}
]
},
"popularity": {
"forks": 1,
"stars": 15,
"watchers": 4,
"fork_history": {
"days": [
{
"date": "2021-02-01",
"count": 1
}
],
"complete": true,
"collected": 1,
"total_forks": 1
},
"star_history": null,
"open_issues_and_prs": 1
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [
"examples"
],
"has_llms_txt": false,
"has_dockerfile": true,
"has_mcp_signal": false,
"bootstrap_files": [
"Makefile",
"contrib/freebsd/Makefile"
],
"api_schema_files": [
"proto/brokerv1/broker.proto"
],
"has_devcontainer": false,
"typecheck_configs": [],
"toolchain_manifests": [
"go.mod"
],
"largest_source_bytes": 29428,
"source_files_sampled": 62,
"oversized_source_files": 0,
"agent_instruction_files": [
"AGENTS.md",
"CLAUDE.md"
],
"agent_instruction_max_bytes": 669
},
"dependencies": {
"manifests": [
"go.mod"
],
"advisories": {
"error": null,
"scope": "repository_graph",
"source": "osv",
"findings": [
{
"name": "golang.org/x/crypto",
"direct": true,
"version": "v0.49.0",
"severity": "critical",
"ecosystem": "go",
"cvss_score": 10,
"advisory_ids": [
"GHSA-45gg-vh54-h5m9",
"GHSA-5cgq-3rg8-m6cv",
"GHSA-78mq-xcr3-xm33",
"GHSA-89gr-r52h-f8rx",
"GHSA-9m57-25v3-79x9",
"GHSA-f5wc-c3c7-36mc",
"GHSA-jppx-rxg9-jmrx",
"GHSA-q4h4-gmj2-qvw2",
"GHSA-qpw4-5x99-6vjp",
"GHSA-rm3j-f69w-wqmq"
],
"fixed_version": "0.52.0",
"advisory_count": 27,
"oldest_advisory_days": 67
},
{
"name": "google.golang.org/grpc",
"direct": true,
"version": "v1.80.0",
"severity": "critical",
"ecosystem": "go",
"cvss_score": 9.1,
"advisory_ids": [
"GHSA-hrxh-6v49-42gf",
"GO-2026-6061"
],
"fixed_version": "1.82.1",
"advisory_count": 2,
"oldest_advisory_days": 6
},
{
"name": "golang.org/x/net",
"direct": false,
"version": "v0.52.0",
"severity": "moderate",
"ecosystem": "go",
"cvss_score": 6.5,
"advisory_ids": [
"GHSA-5cv4-jp36-h3mw",
"GO-2026-4918",
"GO-2026-5025",
"GO-2026-5026",
"GO-2026-5027",
"GO-2026-5028",
"GO-2026-5029",
"GO-2026-5030",
"GO-2026-5942"
],
"fixed_version": "1.26.3",
"advisory_count": 9,
"oldest_advisory_days": 81
},
{
"name": "github.com/go-chi/chi/v5",
"direct": true,
"version": "v5.2.5",
"severity": "unknown",
"ecosystem": "go",
"cvss_score": null,
"advisory_ids": [
"GO-2026-5774",
"GO-2026-5775",
"GO-2026-5777"
],
"fixed_version": "5.3.0",
"advisory_count": 3,
"oldest_advisory_days": 3
},
{
"name": "go.opentelemetry.io/otel",
"direct": false,
"version": "v1.41.0",
"severity": "unknown",
"ecosystem": "go",
"cvss_score": null,
"advisory_ids": [
"GO-2026-5158"
],
"fixed_version": "1.44.0",
"advisory_count": 1,
"oldest_advisory_days": 3
},
{
"name": "golang.org/x/sys",
"direct": false,
"version": "v0.42.0",
"severity": "unknown",
"ecosystem": "go",
"cvss_score": null,
"advisory_ids": [
"GO-2026-5024"
],
"fixed_version": "0.44.0",
"advisory_count": 1,
"oldest_advisory_days": 66
},
{
"name": "golang.org/x/text",
"direct": false,
"version": "v0.35.0",
"severity": "unknown",
"ecosystem": "go",
"cvss_score": null,
"advisory_ids": [
"GO-2026-5970"
],
"fixed_version": "0.39.0",
"advisory_count": 1,
"oldest_advisory_days": 13
}
],
"collected": true,
"malicious": [],
"truncated": false,
"by_severity": {
"unknown": 4,
"critical": 2,
"moderate": 1
},
"advisory_count": 44,
"affected_count": 7,
"assessed_count": 51,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 3
},
"ecosystems": [
"go"
],
"dependencies": [
{
"name": "github.com/alecthomas/kong",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.15.0"
},
{
"name": "github.com/cbroglie/mustache",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.4.0"
},
{
"name": "github.com/coreos/go-oidc/v3",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v3.17.0"
},
{
"name": "github.com/go-chi/chi/v5",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v5.2.5"
},
{
"name": "github.com/int128/oauth2cli",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.18.0"
},
{
"name": "github.com/lmittmann/tint",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.1.3"
},
{
"name": "github.com/mikesmitty/edkey",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.0.0-20170222072505-3356ea4e686a"
},
{
"name": "github.com/pkg/browser",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.0.0-20240102092130-5ac0b6a4141c"
},
{
"name": "github.com/stretchr/testify",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.11.1"
},
{
"name": "golang.org/x/crypto",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.49.0"
},
{
"name": "golang.org/x/oauth2",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.36.0"
},
{
"name": "gotest.tools",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v2.2.0+incompatible"
},
{
"name": "github.com/alecthomas/kong-yaml",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.2.0"
},
{
"name": "github.com/bmatcuk/doublestar/v4",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v4.10.0"
},
{
"name": "github.com/gregjones/httpcache",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.0.0-20190611155906-901d90724c79"
},
{
"name": "github.com/sony/gobreaker/v2",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v2.4.0"
},
{
"name": "github.com/yaronf/httpsign",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.5.1"
},
{
"name": "google.golang.org/grpc",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.80.0"
},
{
"name": "google.golang.org/protobuf",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.36.11"
},
{
"name": "gopkg.in/yaml.v3",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v3.0.1"
}
],
"all_dependencies": {
"error": null,
"source": "github-sbom",
"packages": [
{
"name": "github.com/alecthomas/kong",
"direct": true,
"version": "v1.15.0",
"ecosystem": "go"
},
{
"name": "github.com/alecthomas/kong-yaml",
"direct": true,
"version": "v0.2.0",
"ecosystem": "go"
},
{
"name": "github.com/bmatcuk/doublestar/v4",
"direct": true,
"version": "v4.10.0",
"ecosystem": "go"
},
{
"name": "github.com/cbroglie/mustache",
"direct": true,
"version": "v1.4.0",
"ecosystem": "go"
},
{
"name": "github.com/coreos/go-oidc/v3",
"direct": true,
"version": "v3.17.0",
"ecosystem": "go"
},
{
"name": "github.com/go-chi/chi/v5",
"direct": true,
"version": "v5.2.5",
"ecosystem": "go"
},
{
"name": "github.com/gregjones/httpcache",
"direct": true,
"version": "v0.0.0-20190611155906-901d90724c79",
"ecosystem": "go"
},
{
"name": "github.com/int128/oauth2cli",
"direct": true,
"version": "v1.18.0",
"ecosystem": "go"
},
{
"name": "github.com/lmittmann/tint",
"direct": true,
"version": "v1.1.3",
"ecosystem": "go"
},
{
"name": "github.com/mikesmitty/edkey",
"direct": true,
"version": "v0.0.0-20170222072505-3356ea4e686a",
"ecosystem": "go"
},
{
"name": "github.com/pkg/browser",
"direct": true,
"version": "v0.0.0-20240102092130-5ac0b6a4141c",
"ecosystem": "go"
},
{
"name": "github.com/sony/gobreaker/v2",
"direct": true,
"version": "v2.4.0",
"ecosystem": "go"
},
{
"name": "github.com/stretchr/testify",
"direct": true,
"version": "v1.11.1",
"ecosystem": "go"
},
{
"name": "github.com/yaronf/httpsign",
"direct": true,
"version": "v0.5.1",
"ecosystem": "go"
},
{
"name": "golang.org/x/crypto",
"direct": true,
"version": "v0.49.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/oauth2",
"direct": true,
"version": "v0.36.0",
"ecosystem": "go"
},
{
"name": "google.golang.org/grpc",
"direct": true,
"version": "v1.80.0",
"ecosystem": "go"
},
{
"name": "google.golang.org/protobuf",
"direct": true,
"version": "v1.36.11",
"ecosystem": "go"
},
{
"name": "gopkg.in/yaml.v3",
"direct": true,
"version": "v3.0.1",
"ecosystem": "go"
},
{
"name": "gotest.tools",
"direct": true,
"version": "v2.2.0+incompatible",
"ecosystem": "go"
},
{
"name": "github.com/davecgh/go-spew",
"direct": false,
"version": "v1.1.2-0.20180830191138-d8f796af33cc",
"ecosystem": "go"
},
{
"name": "github.com/decred/dcrd/dcrec/secp256k1/v4",
"direct": false,
"version": "v4.4.0",
"ecosystem": "go"
},
{
"name": "github.com/dunglas/httpsfv",
"direct": false,
"version": "v1.0.2",
"ecosystem": "go"
},
{
"name": "github.com/go-jose/go-jose/v4",
"direct": false,
"version": "v4.1.4",
"ecosystem": "go"
},
{
"name": "github.com/goccy/go-json",
"direct": false,
"version": "v0.10.3",
"ecosystem": "go"
},
{
"name": "github.com/google/go-cmp",
"direct": false,
"version": "v0.7.0",
"ecosystem": "go"
},
{
"name": "github.com/int128/listener",
"direct": false,
"version": "v1.3.0",
"ecosystem": "go"
},
{
"name": "github.com/kr/pretty",
"direct": false,
"version": "v0.3.1",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/blackmagic",
"direct": false,
"version": "v1.0.4",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/dsig",
"direct": false,
"version": "v1.0.0",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/dsig-secp256k1",
"direct": false,
"version": "v1.0.0",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/httpcc",
"direct": false,
"version": "v1.0.1",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/httprc",
"direct": false,
"version": "v1.0.6",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/httprc/v3",
"direct": false,
"version": "v3.0.1",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/iter",
"direct": false,
"version": "v1.0.2",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/jwx/v2",
"direct": false,
"version": "v2.1.2",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/jwx/v3",
"direct": false,
"version": "v3.0.12",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/option",
"direct": false,
"version": "v1.0.1",
"ecosystem": "go"
},
{
"name": "github.com/lestrrat-go/option/v2",
"direct": false,
"version": "v2.0.0",
"ecosystem": "go"
},
{
"name": "github.com/pkg/errors",
"direct": false,
"version": "v0.9.1",
"ecosystem": "go"
},
{
"name": "github.com/pmezard/go-difflib",
"direct": false,
"version": "v1.0.1-0.20181226105442-5d4384ee4fb2",
"ecosystem": "go"
},
{
"name": "github.com/rogpeppe/go-internal",
"direct": false,
"version": "v1.14.1",
"ecosystem": "go"
},
{
"name": "github.com/segmentio/asm",
"direct": false,
"version": "v1.2.1",
"ecosystem": "go"
},
{
"name": "github.com/valyala/fastjson",
"direct": false,
"version": "v1.6.4",
"ecosystem": "go"
},
{
"name": "go.opentelemetry.io/otel",
"direct": false,
"version": "v1.41.0",
"ecosystem": "go"
},
{
"name": "go.opentelemetry.io/otel/sdk/metric",
"direct": false,
"version": "v1.41.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/net",
"direct": false,
"version": "v0.52.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/sync",
"direct": false,
"version": "v0.20.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/sys",
"direct": false,
"version": "v0.42.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/text",
"direct": false,
"version": "v0.35.0",
"ecosystem": "go"
},
{
"name": "google.golang.org/genproto/googleapis/rpc",
"direct": false,
"version": "v0.0.0-20260406210006-6f92a3bedf2d",
"ecosystem": "go"
}
],
"collected": true,
"truncated": false,
"total_count": 51,
"direct_count": 20,
"indirect_count": 31
}
},
"maintainership": {
"issues": {
"open_prs": 1,
"merged_prs": 13,
"open_issues": 0,
"closed_ratio": 1,
"closed_issues": 3,
"closed_unmerged_prs": 12
},
"bus_factor": 1,
"bot_contributors": 1,
"top_contributors": [
{
"type": "User",
"login": "brianm",
"commits": 272,
"avatar_url": "https://avatars.githubusercontent.com/u/1291?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"build.yml",
"release.yml"
],
"has_docs_dir": true,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"go.sum"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "no pull request found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/30 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 10,
"reason": "project has 3 contributing companies or organizations -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 10,
"reason": "update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 9,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 4,
"reason": "5 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 4",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": 10,
"reason": "packaging workflow detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": 0,
"reason": "Project has not signed or included provenance with any releases.",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 0,
"reason": "29 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "ba27e29688043cdf2adc08f8ea470c82837c2c1c",
"ran_at": "2026-07-28T05:46:54Z",
"aggregate_score": 3.7,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-21T15:44:57Z",
"oldest_open_prs": [
{
"number": 29,
"created_at": "2026-04-18T22:30:38Z",
"last_comment_at": "2026-07-19T22:43:30Z",
"last_comment_author": "brianm"
}
],
"last_merged_pr_at": "2026-02-21T22:50:17Z",
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/epithet-ssh/epithet",
"host": "github.com",
"name": "epithet",
"owner": "epithet-ssh"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": "The weighted overall 56 is calibrated to 59 on the published index scale (record calibration 2026-08-02).",
"notes": [
{
"code": "overall_calibration",
"params": {
"raw": 56,
"calibrated": 59,
"calibration": "2026-08-02"
}
}
],
"value": 59,
"inputs": {
"security": 42,
"vitality": 77,
"community": 32,
"governance": 55,
"calibration": "2026-08-02",
"engineering": 62,
"ai_readiness": 78,
"weighted_overall_raw": 56
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 77,
"weight": 0.21,
"metrics": [
{
"key": "development_activity",
"band": "good",
"name": "Development activity",
"note": null,
"notes": [],
"value": 68,
"inputs": {
"commits_last_year": 231,
"human_commit_share": 1,
"days_since_last_push": 8,
"active_weeks_last_year": 25
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 8 days ago",
"points": 28.8,
"status": "partial",
"details": [
{
"code": "push_recency",
"params": {
"days": 8
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "25/52 weeks with commits",
"points": 17.3,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 25
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "231 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 231
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "5 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 4",
"points": 4,
"status": "partial",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": null,
"notes": [],
"value": 90,
"inputs": {
"releases_count": 57,
"latest_release_tag": "v0.17.3",
"releases_from_tags": false,
"days_since_latest_release": 8,
"mean_days_between_releases": 10.8
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "57 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 57
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 8 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 8
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~10.8 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 10.8
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "exceptional",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "maintained",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": null,
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": 14,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "last human commit 14 days ago",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_maintained",
"params": {
"days": 14
}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "at_risk",
"name": "Community & Adoption",
"value": 32,
"weight": 0.17,
"metrics": [
{
"key": "popularity",
"band": "at_risk",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 21,
"inputs": {
"forks": 1,
"stars": 15,
"watchers": 4,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "15 stars",
"points": 18.6,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 15
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "1 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 1
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "4 watchers",
"points": 2.7,
"status": "partial",
"details": [
{
"code": "watchers",
"params": {
"count": 4
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "weak",
"name": "Community health",
"note": null,
"notes": [],
"value": 44,
"inputs": {
"has_readme": true,
"has_license": true,
"readme_badges": null,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"readme_badge_services": [],
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "license file present, not a recognized license",
"points": 16.9,
"status": "partial",
"details": [
{
"code": "license_custom",
"params": {}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "moderate",
"name": "Sustainability & Governance",
"value": 55,
"weight": 0.23,
"metrics": [
{
"key": "maintainer_resilience",
"band": "at_risk",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 20,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 1,
"top_contributor_share": 1
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 3 contributing companies or organizations -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "good",
"name": "Issue & PR responsiveness",
"note": "Excluded from scoring (no data or not applicable): Newcomer PR acceptance. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"newcomer_pr_acceptance"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 66,
"inputs": {
"merged_prs": 13,
"open_issues": 0,
"closed_issues": 3,
"prs_merged_7d": null,
"prs_decided_7d": null,
"prs_merged_30d": null,
"prs_decided_30d": null,
"issue_closed_ratio": 1,
"closed_unmerged_prs": 12,
"first_time_authors_30d": null,
"first_time_prs_merged_30d": null,
"first_time_prs_decided_30d": null
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "100% of issues closed",
"points": 42,
"status": "met",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 100
}
}
],
"max_points": 42
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "13/25 decided PRs merged",
"points": 15.6,
"status": "partial",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 13,
"decided": 25
}
}
],
"max_points": 30
},
{
"key": "newcomer_pr_acceptance",
"name": "Newcomer PR acceptance",
"detail": "no first-time contributor's PR decided in 30d",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_newcomer_prs",
"params": {
"days": 30
}
}
],
"max_points": 13
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "moderate",
"name": "Ownership & stewardship",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"followers": 0,
"owner_type": "Organization",
"is_verified": null,
"owner_login": "epithet-ssh",
"public_repos": 11,
"account_age_days": 2467
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "organization-owned",
"points": 30,
"status": "met",
"details": [
{
"code": "owner_organization",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "0 followers of epithet-ssh",
"points": 0,
"status": "missed",
"details": [
{
"code": "owner_followers",
"params": {
"count": 0,
"login": "epithet-ssh"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "11 public repos, account ~6 yr old",
"points": 19.9,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 11
}
},
{
"code": "account_age_years",
"params": {
"years": 6
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "exceptional",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"github.com/epithet-ssh/epithet"
],
"ecosystems": "go",
"any_deprecated": false,
"min_days_since_publish": 8
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on go",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "go"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 8 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 8
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "69 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 69
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "moderate",
"name": "Engineering Quality",
"value": 62,
"weight": 0.19,
"metrics": [
{
"key": "engineering_practices",
"band": "moderate",
"name": "Engineering practices",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 60,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "2 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 2
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "good",
"name": "Documentation",
"note": null,
"notes": [],
"value": 65,
"inputs": {
"topics": [],
"has_wiki": false,
"homepage": null,
"has_readme": true,
"has_docs_dir": true,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "weak",
"name": "Security",
"value": 42,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "weak",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 37,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 17,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 1,
"scorecard_aggregate": 3.7
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 3 contributing companies or organizations -- score normalized to 10",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "update tool detected",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.2,
"status": "partial",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "5 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 4",
"points": 3,
"status": "partial",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "29 existing vulnerabilities detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "dependency_advisories",
"band": "moderate",
"name": "Dependency advisories",
"note": "Excluded from scoring (no data or not applicable): Indirect dependencies free of known advisories. Remaining weights renormalized. Matched 51 resolved dependencies against OSV. This repository publishes no package the index resolves, so the repository dependency graph was assessed instead. That graph mixes development and test pins with shipped dependencies, so only the declared runtime dependencies are scored; transitive findings are reported as context and excluded from the score. Reachability is not analyzed.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"indirect_dependencies_free_of_known_advisories"
]
}
},
{
"code": "weights_renormalized",
"params": {}
},
{
"code": "advisories_scope_repository",
"params": {
"assessed": 51
}
},
{
"code": "advisories_repo_graph_caveat",
"params": {}
},
{
"code": "advisories_reachability",
"params": {}
}
],
"value": 61,
"inputs": {
"source": "osv",
"advisories": 44,
"affected_packages": 7,
"assessed_packages": 51,
"unassessed_packages": 0,
"affected_by_severity": "critical 2, moderate 1, unknown 4",
"direct_affected_packages": 3
},
"components": [
{
"key": "direct_dependencies_free_of_known_advisories",
"name": "Direct dependencies free of known advisories",
"detail": "3 affected: golang.org/x/crypto v0.49.0 (critical 10.0), google.golang.org/grpc v1.80.0 (critical 9.1), github.com/go-chi/chi/v5 v5.2.5 (unknown)",
"points": 5.4,
"status": "partial",
"details": [
{
"code": "advisories_affected",
"params": {
"count": 3,
"packages": "golang.org/x/crypto v0.49.0 (critical 10.0), google.golang.org/grpc v1.80.0 (critical 9.1), github.com/go-chi/chi/v5 v5.2.5 (unknown)"
}
}
],
"max_points": 35
},
{
"key": "indirect_dependencies_free_of_known_advisories",
"name": "Indirect dependencies free of known advisories",
"detail": "transitive set not separable from development and test dependencies in this scope",
"points": 0,
"status": "excluded",
"details": [
{
"code": "advisories_scope_not_separable",
"params": {}
}
],
"max_points": 25
},
{
"key": "no_advisories_left_outstanding",
"name": "No advisories left outstanding",
"detail": "no advisory has been public longer than 90 days",
"points": 40,
"status": "met",
"details": [
{
"code": "advisories_none_stale",
"params": {
"days": 90
}
}
],
"max_points": 40
}
]
},
{
"key": "malicious_dependencies",
"band": "exceptional",
"name": "Malicious dependencies",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"source": "osv",
"meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
"packages": [],
"red_flag": false,
"assessed_packages": 51,
"malicious_packages": 0,
"direct_malicious_packages": 0,
"withdrawn_malicious_packages": 0,
"installable_malicious_packages": 0
},
"components": [
{
"key": "no_dependency_reported_as_a_malicious_package",
"name": "No dependency reported as a malicious package",
"detail": "no dependency is reported as a malicious package",
"points": 100,
"status": "met",
"details": [
{
"code": "no_malicious_dependencies",
"params": {}
}
],
"max_points": 100
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "exceptional",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"commit_weight_rule": {
"min_commits": 50,
"min_commit_share": 0.1
},
"review_only_matches": 0,
"below_threshold_exposures": [],
"assessed_self_published_locations": 2
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "good",
"name": "AI Readiness",
"value": 78,
"weight": 0.04,
"metrics": [
{
"key": "ai_agent_context",
"band": "excellent",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 84,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.74,
"agent_instruction_files": [
"AGENTS.md",
"CLAUDE.md"
],
"agent_instruction_max_bytes": 669
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "AGENTS.md, CLAUDE.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "AGENTS.md, CLAUDE.md"
}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "74 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 39.5,
"status": "partial",
"details": [
{
"code": "legible_history",
"params": {
"legible": 74,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "good",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 65,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"go.sum"
],
"has_dockerfile": true,
"typed_language": true,
"bootstrap_files": [
"Makefile",
"contrib/freebsd/Makefile"
],
"has_devcontainer": false,
"has_linter_config": false,
"typecheck_configs": [],
"agent_commit_share": 0.02,
"toolchain_manifests": [
"go.mod"
],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": "Makefile, contrib/freebsd/Makefile",
"points": 18,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Makefile, contrib/freebsd/Makefile"
}
}
],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "Go (statically typed)",
"points": 11,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "Dockerfile, lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Dockerfile, lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "2 of the last 100 commits agent-authored or agent-credited",
"points": 4,
"status": "partial",
"details": [
{
"code": "agent_authored_commits",
"params": {
"count": 2,
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "exceptional",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"primary_language": "Go",
"largest_source_bytes": 29428,
"source_files_sampled": 62,
"oversized_source_files": 0
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Go (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "0/62 source files over 60KB",
"points": 55,
"status": "met",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 62,
"oversized": 0
}
}
],
"max_points": 55
}
]
},
{
"key": "ai_interfaces",
"band": "excellent",
"name": "Machine-readable interfaces",
"note": null,
"notes": [],
"value": 80,
"inputs": {
"example_dirs": [
"examples"
],
"has_mcp_signal": false,
"api_schema_files": [
"proto/brokerv1/broker.proto"
]
},
"components": [
{
"key": "api_schema_openapi_graphql_proto",
"name": "API schema (OpenAPI/GraphQL/proto)",
"detail": "proto/brokerv1/broker.proto",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "proto/brokerv1/broker.proto"
}
}
],
"max_points": 40
},
{
"key": "mcp_server",
"name": "MCP server",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "runnable_examples",
"name": "Runnable examples",
"detail": "examples",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "examples"
}
}
],
"max_points": 40
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)."
}
],
"classification": {
"labels": [
"library"
],
"scores": {
"library": 6,
"network-service": 3
},
"primary": "library",
"evidence": [
{
"tier": "distribution",
"label": "library",
"source": "registry:go",
"weight": 6
},
{
"tier": "structure",
"label": "network-service",
"source": "api_schema",
"weight": 3
}
],
"artifacts": [],
"confidence": "medium",
"host_extension": false,
"runs_as_process": false,
"consumed_by_code": true
},
"metrics_version": "2.3.1"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token"
],
"report_type": "repository",
"generated_at": "2026-07-28T05:47:00.252466Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/e/epithet-ssh/epithet.svg",
"full_name": "epithet-ssh/epithet",
"license_state": "custom",
"license_spdx": null
}