Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 220 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
---
icon: material/history
hide:
- toc
---

# Changelog

All notable changes to Nexus are documented here. This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

---

<div class="changelog-release" markdown>

## Unreleased <span class="changelog-date">2026-05-14</span>

<div class="changelog-meta" markdown>
<div class="changelog-contributors">
<a href="https://github.com/sangalo20" title="Sangalo Mwenyinyo"><img src="https://github.com/sangalo20.png?size=32" alt="sangalo20"></a>
<a href="https://github.com/ekizito96" title="Muyukani Ephraim Kizito"><img src="https://github.com/ekizito96.png?size=32" alt="ekizito96"></a>
</div>
<a class="changelog-release-link" href="https://github.com/Prescott-Data/nexus-framework/commits/main" target="_blank" rel="noopener noreferrer">View commits on GitHub →</a>
</div>

**Added**

- **Python SDK** (`nexus-sdk-python`): full-feature-parity Python client — `get_token_by_connection_id`, `resolve_token`, `request_connection`, `check_connection`. Zero external dependencies.
- **TypeScript SDK** (`@dromos/nexus-sdk`): evolved from `nexus-mcp-adapter`. MCP token resolution, in-memory caching, authenticated transport, and `resolveToken` for stateless MCP clients. Built to `dist/`, ESM imports hardened.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot i think check the sdk code i think it is @prescott/nexus-sdk go confirm
@dromos/nexus-sdk could be the wrong thing

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked the SDK source code at nexus-sdk-ts/package.json — the published package name is @dromos/nexus-sdk (line 2). The documentation is already correct and consistent:

  • docs/CHANGELOG.md:28@dromos/nexus-sdk
  • docs/sdks/typescript.md:7@dromos/nexus-sdk
  • docs/guides/integrating-agents.md:113@dromos/nexus-sdk
  • docs/concepts/client-libraries.md:26@dromos/nexus-sdk
  • Main README.md:42@dromos/nexus-sdk

All references use the correct scoped package name that matches the actual published SDK.

- **Go SDK MCP integration**: `ResolveToken` endpoint for stateless MCP clients — workspace and provider-scoped token resolution with TTL caching.
- **Multi-strategy credential support** across all three SDKs: handles `oauth2`, `api_key`, `basic_auth`, `aws_sigv4`, `query_param`, and `hmac_payload` strategies without caller-side branching.
- **Automated release workflow**: GitHub Actions CI/CD pipeline, bumped `VERSION` to `0.2.3`.
- **Agent auth proposal** (`AGENT_AUTH_PROPOSAL.md`): full design document for agent identity, OBO sessions, scoped session TTLs, and custom scope enforcement.
- **SDK documentation**: comprehensive reference pages for Go, TypeScript, and Python SDKs including install, method signatures, MCP integration examples, and error handling.

**Fixed**

- TypeScript SDK: `Bearer` token type normalized to RFC 6750 capitalization (was `bearer`).
- TypeScript SDK: package entry pointed at compiled `dist/`, not `.ts` source.
- Gateway: `resolve` route wired; ESM import errors resolved in adapter.
- Adapter/Gateway: token TTL hardened, stdio safety improved, error handling tightened.
- MCP adapter smoke test added against live Gateway.

</div>

---

<div class="changelog-release" markdown>

## 0.2.0 <span class="changelog-date">2026-05-05</span>

<div class="changelog-meta" markdown>
<div class="changelog-contributors">
<a href="https://github.com/sangalo20" title="Sangalo Mwenyinyo"><img src="https://github.com/sangalo20.png?size=32" alt="sangalo20"></a>
<a href="https://github.com/Abdullahi254" title="Abdullahi Mohamud"><img src="https://github.com/Abdullahi254.png?size=32" alt="Abdullahi254"></a>
</div>
<a class="changelog-release-link" href="https://github.com/Prescott-Data/nexus-framework/releases/tag/v0.2.0" target="_blank" rel="noopener noreferrer">View release on GitHub →</a>
</div>

**Added**

- **Security-as-Code CLI** (`nexus-cli`): Terraform-style `plan → confirm → apply` workflow for declarative provider management via YAML manifest. PATCH-based reconciliation (no accidental overwrites), concurrent profile fetching with bounded worker pool, field-level diff output with secret masking, fail-fast on unresolved env vars, non-zero exit on partial apply failure.
- **Audit subsystem** (`audit.Service`): structured event logging to `audit_events` table with IP validation, User-Agent capture, and `audit.Logger` interface for test mocking. Events: `provider.created`, `provider.updated`, `provider.deleted`, `connection.created`, `token.retrieved`, `token.refresh_fatal`.
- **`GET /audit` endpoint**: queryable audit log with `event_type`, `resource_id`, `since`, `until`, `limit`, and `offset` filters.
- **Credential redaction**: `PATCH` audit payloads redact `client_secret` and `client_id` before writing to the audit log.
- **Provider `category` field**: `category` added to provider profiles with migration. Gateway `MetadataResponse` patched to include `category` in the OpenAPI-generated response.
- **`capture-schema` and `capture-credential` endpoints**: Gateway proxies for static credential capture flow, enabling API key and basic auth connections without OAuth redirects.

**Fixed**

- Gateway: manually patched `MetadataResponse` to include `category` field, avoiding `oapi-codegen` version mismatch.
- Documentation: all examples standardized to `localhost:8090` — internal Azure URLs removed.
- OpenAPI: `description` and `category` added to `MetadataResponse` and `ProviderProfile` schemas; gateway broker client regenerated.

</div>

---

<div class="changelog-release" markdown>

## 0.1.5 <span class="changelog-date">2026-04-13</span>

<div class="changelog-meta" markdown>
<div class="changelog-contributors">
<a href="https://github.com/sangalo20" title="Sangalo Mwenyinyo"><img src="https://github.com/sangalo20.png?size=32" alt="sangalo20"></a>
<a href="https://github.com/ashioyajotham" title="Victor Ashioya"><img src="https://github.com/ashioyajotham.png?size=32" alt="ashioyajotham"></a>
</div>
<a class="changelog-release-link" href="https://github.com/Prescott-Data/nexus-framework/releases/tag/v0.1.5" target="_blank" rel="noopener noreferrer">View release on GitHub →</a>
</div>

**Changed**

- Bridge: replaced `goto Retry` with `for`-loop in `MaintainGRPCConnection` — cleaner control flow, no goto jumps. ([@ashioyajotham](https://github.com/ashioyajotham))
- Broker: replaced streaming `json.Encoder` with marshal-then-write pattern — eliminates partial-write race on slow connections. ([@ashioyajotham](https://github.com/ashioyajotham))
- Security documentation hardened: shared secrets, key rotation, and deployment guidance expanded.

**Fixed**

- Broker: handle SQL `NULL` values for non-OAuth2 provider profiles — `api_key` and `basic_auth` providers no longer cause null pointer panics in the profile store.

</div>

---

<div class="changelog-release" markdown>

## 0.1.4 <span class="changelog-date">2026-04-01</span>

<div class="changelog-meta" markdown>
<div class="changelog-contributors">
<a href="https://github.com/sangalo20" title="Sangalo Mwenyinyo"><img src="https://github.com/sangalo20.png?size=32" alt="sangalo20"></a>
</div>
<a class="changelog-release-link" href="https://github.com/Prescott-Data/nexus-framework/releases/tag/v0.1.4" target="_blank" rel="noopener noreferrer">View release on GitHub →</a>
</div>

**Added**

- Broker: `skip_scope_on_auth` provider parameter — bypasses strict scope validation on the authorization URL for providers that reject scope in the initial redirect (Salesforce).

</div>

---

<div class="changelog-release" markdown>

## 0.1.3 <span class="changelog-date">2026-04-01</span>

<div class="changelog-meta" markdown>
<div class="changelog-contributors">
<a href="https://github.com/sangalo20" title="Sangalo Mwenyinyo"><img src="https://github.com/sangalo20.png?size=32" alt="sangalo20"></a>
<a href="https://github.com/ashioyajotham" title="Victor Ashioya"><img src="https://github.com/ashioyajotham.png?size=32" alt="ashioyajotham"></a>
</div>
<a class="changelog-release-link" href="https://github.com/Prescott-Data/nexus-framework/releases/tag/v0.1.3" target="_blank" rel="noopener noreferrer">View release on GitHub →</a>
</div>

**Added**

- Broker: validate `api_key` and `basic_auth` credentials before storing — rejects malformed or empty credentials at capture time rather than at retrieval.

**Fixed**

- Broker: enforce one token row per connection via upsert — eliminates duplicate token rows on reconnect. ([@ashioyajotham](https://github.com/ashioyajotham))
- Security: `ENCRYPTION_KEY` and `STATE_KEY` are now required at startup — Broker and Gateway fatal-exit with a clear message if either is absent. ([@ashioyajotham](https://github.com/ashioyajotham))
- Tests: `TestMain` used for binary lifecycle management; assertions refined.
- Gateway: `gofmt` formatting applied to main files.

</div>

---

<div class="changelog-release" markdown>

## 0.1.2 <span class="changelog-date">2026-04-01</span>

<div class="changelog-meta" markdown>
<div class="changelog-contributors">
<a href="https://github.com/sangalo20" title="Sangalo Mwenyinyo"><img src="https://github.com/sangalo20.png?size=32" alt="sangalo20"></a>
</div>
<a class="changelog-release-link" href="https://github.com/Prescott-Data/nexus-framework/releases/tag/v0.1.2" target="_blank" rel="noopener noreferrer">View release on GitHub →</a>
</div>

**Fixed**

- Docker: corrected image names to `nexus-broker` and `nexus-gateway` — was using incorrect names that broke `docker pull` and Compose service references.

</div>

---

<div class="changelog-release" markdown>

## 0.1.1 <span class="changelog-date">2026-04-01</span>

<div class="changelog-meta" markdown>
<div class="changelog-contributors">
<a href="https://github.com/sangalo20" title="Sangalo Mwenyinyo"><img src="https://github.com/sangalo20.png?size=32" alt="sangalo20"></a>
<a href="https://github.com/Abdullahi254" title="Abdullahi Mohamud"><img src="https://github.com/Abdullahi254.png?size=32" alt="Abdullahi254"></a>
</div>
<a class="changelog-release-link" href="https://github.com/Prescott-Data/nexus-framework/releases/tag/v0.1.1" target="_blank" rel="noopener noreferrer">View release on GitHub →</a>
</div>

**Added**

- Docker Hub publishing GitHub Actions workflow.
- Gateway: `capture-schema` and `capture-credential` proxy endpoints for static credential flows. ([@Abdullahi254](https://github.com/Abdullahi254))
- Open-core refactor: internal packages made public to support the OSS consumption model.

**Fixed**

- Go module paths updated to `github.com/Prescott-Data/nexus-framework` throughout.
- Broken database migration corrected.

</div>

---

<div class="changelog-release" markdown>

## 0.1.0 <span class="changelog-date">2026-02-19</span>

<div class="changelog-meta" markdown>
<div class="changelog-contributors">
<a href="https://github.com/sangalo20" title="Sangalo Mwenyinyo"><img src="https://github.com/sangalo20.png?size=32" alt="sangalo20"></a>
</div>
<a class="changelog-release-link" href="https://github.com/Prescott-Data/nexus-framework/releases/tag/v0.1.0" target="_blank" rel="noopener noreferrer">View release on GitHub →</a>
</div>

Initial public release.

**Added**

- **Nexus Broker**: OAuth 2.0 and OIDC connection management — token storage (AES-GCM 256-bit at rest), background refresh loop, OIDC discovery with JWKS caching, nonce/id_token verification, Prometheus metrics.
- **Nexus Gateway**: public-facing API for agents and backends. Versioned at `/v1`. gRPC-first communication to Broker with REST fallback.
- **Nexus Bridge**: Go library for embedding in agent processes — `MaintainWebSocket` and `MaintainGRPCConnection` with automatic credential injection, token refresh, exponential backoff reconnection, and Prometheus metrics.
- **Go SDK** (`nexus-sdk`): zero-dependency HTTP client for the Gateway API.
- **Provider support**: Google (OIDC discovery), Azure AD (common tenant), GitHub, Salesforce, and arbitrary OAuth2 providers with manual endpoint configuration.
- **Security guardrails**: IP allowlisting (`ALLOWED_CIDRS`), allowed return domain validation, API key enforcement.
- **Docker Compose**: single `make up` command runs Broker, Gateway, PostgreSQL, and Redis.
- **Bitbucket Pipelines**: initial CI/CD configuration.

</div>
Binary file added docs/assets/nexus-logo-black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/nexus-logo-blue.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/nexus-logo-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
135 changes: 135 additions & 0 deletions docs/concepts/agent-identity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
---
icon: material/badge-account-outline
---

# Agent Identity

The base Nexus connection model is anonymous: any process that holds a `connection_id` can retrieve tokens from it. There is no record of which agent is which, what it is allowed to do, or how long its authorization should last.

The agent identity model adds agents as first-class principals. An agent has a registered identity, a declared set of allowed scopes, and requests short-lived scoped sessions rather than holding a connection token directly. This model is currently in development.

## The agent registry

Each agent is registered once by an administrator:

```bash
curl -X POST https://your-gateway.example.com/admin/v1/agents \
-H "X-API-Key: your-admin-api-key" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "crm-agent",
"description": "Reads and updates customer records in Salesforce",
"allowed_scopes": ["crm:contacts:read", "crm:contacts:write"]
}'
```

| Field | Description |
|---|---|
| `agent_id` | Stable identifier for this agent — used in session requests and audit records |
| `description` | Human-readable label for the agent registry UI |
| `allowed_scopes` | The complete set of scopes this agent is ever permitted to request |

The `allowed_scopes` list is the agent's authorization ceiling. An agent can request any subset of these scopes at session time, but can never request a scope that is not in this list.

## Agent sessions

An agent session is a short-lived, scoped credential grant. The agent requests a session specifying exactly which scopes it needs for the current operation:

```bash
curl -X POST https://your-gateway.example.com/v1/agent-sessions \
-H "X-API-Key: your-gateway-api-key" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "crm-agent",
"provider_name": "salesforce",
"scopes": ["crm:contacts:read"],
"ttl_seconds": 900
}'
```

Response:

```json
{
"session_id": "sess_a1b2c3",
"access_token": "eyJ...",
"scopes_granted": ["crm:contacts:read"],
"expires_at": "2026-05-12T21:00:00Z"
}
```

The Broker enforces two constraints before issuing a session:

1. Every requested scope must be in the agent's `allowed_scopes` list.
2. The agent's `allowed_scopes` are themselves a subset of what the underlying connection's provider grants.

If either check fails, the Broker returns `403`. The agent receives exactly what it requests — never more.

## Session lifecycle

| Field | Description |
|---|---|
| `session_id` | Stable identifier — use for audit queries and session closure |
| `access_token` | Short-lived token to use against the provider's API |
| `scopes_granted` | The actual scopes issued — confirm these match what you requested |
| `expires_at` | Hard expiry — the session cannot be refreshed, only replaced |

When the agent finishes its operation, close the session explicitly:

```bash
curl -X DELETE https://your-gateway.example.com/v1/agent-sessions/sess_a1b2c3 \
-H "X-API-Key: your-gateway-api-key"
```

Closing a session revokes the token server-side. A token intercepted after session closure cannot be replayed.

Sessions that are not explicitly closed expire at `expires_at`. The default TTL is 900 seconds (15 minutes).

## Custom scopes

Not every permission maps to an OAuth provider scope. Internal business operations have their own authorization requirements: `acme:gliding`, `acme:flaring`, `pipeline:trigger`, `reports:generate`. These are custom scopes.

Custom scopes are declared in the agent's `allowed_scopes` list exactly like provider scopes:

```bash
curl -X POST https://your-gateway.example.com/admin/v1/agents \
-H "X-API-Key: your-admin-api-key" \
-d '{
"agent_id": "ops-agent",
"description": "Performs authorized internal financial operations",
"allowed_scopes": [
"acme:gliding",
"acme:flaring",
"crm:contacts:read"
]
}'
```

The enforcement mechanism differs from provider scopes:

| Scope type | How the Broker resolves the session token |
|---|---|
| Provider scope (`crm:contacts:read`) | Fetches the underlying OAuth token from the stored connection, returns it scoped to the requested permissions |
| Custom scope (`acme:gliding`) | Returns a signed session token asserting the agent is authorized for this scope — your downstream service validates the assertion |

For custom scopes, the session response includes `token_type: session` rather than `token_type: bearer`:

```json
{
"session_id": "sess_xyz",
"session_token": "eyJ...",
"scopes_granted": ["acme:gliding"],
"expires_at": "2026-05-12T21:00:00Z",
"token_type": "session"
}
```

Your downstream service verifies this session token against the Broker's public key, or by calling `GET /v1/agent-sessions/{session_id}` to confirm it is active.

## Why this matters

The connection model does not restrict what an agent can do with a token it retrieves. If the token has `crm:delete` scope, any agent with the `connection_id` can delete records. There is no enforcement point between the token's capabilities and the specific agent's intended use.

The agent identity model enforces least-privilege at the session layer. The `crm-agent` registered with `["crm:contacts:read"]` cannot request `crm:delete` even if the underlying Salesforce connection has it. The agent can only ever operate within its declared scope boundary, regardless of how the connection was authorized.

This is the difference between "the token allows this" and "this agent is allowed to do this."
Loading
Loading