@integrity-labs/cloud-broker 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -18
- package/dist/index.js +13 -13
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# `@integrity-labs/cloud-broker`
|
|
2
2
|
|
|
3
|
-
MCP server for the Augmented ephemeral cloud-access broker. Exposes the agent-facing tools (`
|
|
3
|
+
MCP server for the Augmented ephemeral cloud-access broker. Exposes the agent-facing tools (`aws_request_access`, `aws_poll_grant`, `aws_release_access`, `aws_describe_scope`, `aws_preview_request`, `aws_get_credentials`) that mint, poll, and release scoped, TTL-bounded cloud credentials for a single task.
|
|
4
4
|
|
|
5
|
-
**v1 ships AWS support** (STS AssumeRole under the hood; pair with the `aws-cli` toolkit or any AWS SDK as the consumer). GCP, Azure, and Cloudflare land in this same package as
|
|
5
|
+
**v1 ships AWS support** (STS AssumeRole under the hood; pair with the `aws-cli` toolkit or any AWS SDK as the consumer). All tools are namespaced `aws_*` so GCP, Azure, and Cloudflare can land in this same package as `gcp_*` / `azure_*` / `cf_*` siblings without colliding (ENG-4782).
|
|
6
6
|
|
|
7
7
|
See the [PRD](../../docs/prds/aws-ephemeral-access.md) and the [toolkit doc](../../docs/toolkits/aws.md) for the full design.
|
|
8
8
|
|
|
@@ -10,18 +10,18 @@ See the [PRD](../../docs/prds/aws-ephemeral-access.md) and the [toolkit doc](../
|
|
|
10
10
|
|
|
11
11
|
| Tool | Purpose |
|
|
12
12
|
|---|---|
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
13
|
+
| `aws_describe_scope` | Returns the team's resolved policy ceiling for an account — what the agent is allowed to ask for. Free, idempotent. |
|
|
14
|
+
| `aws_preview_request` | Dry-run a candidate request: `auto_approve` / `route_to_approver` / `hard_deny`. Writes nothing. |
|
|
15
|
+
| `aws_request_access` | Mint or queue a grant. On `auto_approve` you get `secret_ref`; on `route_to_approver` you get `pending` and a `grant_id`. |
|
|
16
|
+
| `aws_poll_grant` | Single-shot status check. Escape hatch — the broker pushes resolution via direct-chat. |
|
|
17
|
+
| `aws_get_credentials` | Fetch the AWS_* values for an active grant. Call after `aws_request_access` returns active or after the resolution-notification arrives. |
|
|
18
|
+
| `aws_release_access` | Voluntarily release a grant before TTL. Idempotent. |
|
|
18
19
|
|
|
19
20
|
## Environment
|
|
20
21
|
|
|
21
22
|
| Var | Purpose |
|
|
22
23
|
|---|---|
|
|
23
24
|
| `AGT_HOST` | Augmented API base URL (e.g. `https://api.augmented.example`). |
|
|
24
|
-
| `AGT_TEAM_SLUG` | Team slug for the `X-Team-Slug` header. |
|
|
25
25
|
| `AGT_TOKEN` | Pre-provisioned JWT (preferred). If set, used until expiry. |
|
|
26
26
|
| `AGT_API_KEY` | Host API key (`tlk_…`). Used to refresh the JWT via `/host/exchange` when `AGT_TOKEN` is missing or expired. |
|
|
27
27
|
|
|
@@ -33,10 +33,10 @@ An agent that needs to read one S3 object:
|
|
|
33
33
|
|
|
34
34
|
```jsonc
|
|
35
35
|
// 1. Optional: inspect the envelope before guessing.
|
|
36
|
-
|
|
36
|
+
aws_describe_scope({ account_id: "123456789012" })
|
|
37
37
|
|
|
38
38
|
// 2. Optional: dry-run.
|
|
39
|
-
|
|
39
|
+
aws_preview_request({
|
|
40
40
|
account_id: "123456789012",
|
|
41
41
|
actions: ["s3:GetObject", "s3:ListBucket"],
|
|
42
42
|
resources: ["arn:aws:s3:::reports/*", "arn:aws:s3:::reports"],
|
|
@@ -46,7 +46,7 @@ preview_request({
|
|
|
46
46
|
// → { "would": "auto_approve", "reason": null }
|
|
47
47
|
|
|
48
48
|
// 3. Mint.
|
|
49
|
-
|
|
49
|
+
aws_request_access({
|
|
50
50
|
agent_id: "11111111-1111-4111-8111-111111111111",
|
|
51
51
|
run_id: "22222222-2222-4222-8222-222222222222",
|
|
52
52
|
account_id: "123456789012",
|
|
@@ -58,21 +58,24 @@ request_access({
|
|
|
58
58
|
})
|
|
59
59
|
// → { "grant_id": "...", "status": "active", "secret_ref": "secret_ref://aws/runs/<run_id>/<grant_id>", "expires_at": "..." }
|
|
60
60
|
|
|
61
|
-
// 4.
|
|
62
|
-
|
|
61
|
+
// 4. Fetch the AWS_* values and use them.
|
|
62
|
+
aws_get_credentials({ grant_id: "..." })
|
|
63
|
+
// → { "grant_id": "...", "expires_at": "...", "credentials": { "access_key_id": "...", "secret_access_key": "...", "session_token": "..." } }
|
|
64
|
+
// Bash: AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_SESSION_TOKEN=... aws s3 cp s3://reports/today.csv -
|
|
63
65
|
|
|
64
66
|
// 5. (Optional) release early.
|
|
65
|
-
|
|
67
|
+
aws_release_access({ grant_id: "..." })
|
|
66
68
|
```
|
|
67
69
|
|
|
68
|
-
If `
|
|
70
|
+
If `aws_request_access` returns `status: "pending"`, a human approver was paged. The broker pushes the resolution to you via direct-chat — save the `grant_id`, return control, and resume when the inbound message arrives. On `denied`, the `denial_reason` field explains why. `aws_poll_grant` is an escape hatch for explicit re-checks.
|
|
69
71
|
|
|
70
72
|
## Running locally
|
|
71
73
|
|
|
72
74
|
```bash
|
|
73
75
|
pnpm --filter @integrity-labs/cloud-broker build
|
|
74
76
|
AGT_HOST=http://api.agt.localhost:1355 \
|
|
75
|
-
|
|
77
|
+
AGT_AGENT_ID=<your-agent-uuid> \
|
|
78
|
+
AGT_RUN_ID=<your-run-uuid> \
|
|
76
79
|
AGT_TOKEN=$YOUR_JWT \
|
|
77
80
|
node packages/cloud-broker/dist/index.js
|
|
78
81
|
```
|
|
@@ -81,5 +84,6 @@ The server speaks MCP over stdio. Wire it into your runtime adapter's `.mcp.json
|
|
|
81
84
|
|
|
82
85
|
## Notes
|
|
83
86
|
|
|
84
|
-
- The MCP response strips inline credentials from `
|
|
85
|
-
- Per PRD §6.3 v1 ships TTL-bounded revocation only. `
|
|
87
|
+
- The MCP response strips inline credentials from `aws_request_access` — only the `secret_ref` pointer reaches the LLM. The runtime adapter resolves the pointer at AWS-SDK call time (or via `aws_get_credentials`) so credentials never enter the agent's transcript.
|
|
88
|
+
- Per PRD §6.3 v1 ships TTL-bounded revocation only. `aws_release_access` marks the grant `revoked` in the broker DB and tears down the `secret_ref`, but in-flight STS sessions remain valid in AWS until their TTL. v1.1 closes that gap with the `aws:TokenIssueTime` hard-revoke pattern.
|
|
89
|
+
- **0.6.0 hard-renamed the tools to the `aws_*` namespace (ENG-4782).** Agents on cloud-broker ≤ 0.5.0 will see "tool not found" errors from the broker until they're re-provisioned with the new tool names. Re-run `agt agent provision` for any agent that has the cloud-broker MCP wired in.
|
package/dist/index.js
CHANGED
|
@@ -21214,8 +21214,8 @@ var getCredentialsShape = getCredentialsSchema.shape;
|
|
|
21214
21214
|
// package.json
|
|
21215
21215
|
var package_default = {
|
|
21216
21216
|
name: "@integrity-labs/cloud-broker",
|
|
21217
|
-
version: "0.
|
|
21218
|
-
description: "Cloud Access Broker \u2014 MCP server that mints scoped, TTL-bounded cloud credentials per agent task. v1 ships AWS support (
|
|
21217
|
+
version: "0.6.0",
|
|
21218
|
+
description: "Cloud Access Broker \u2014 MCP server that mints scoped, TTL-bounded cloud credentials per agent task. v1 ships AWS support (aws_request_access, aws_poll_grant, aws_release_access, aws_describe_scope, aws_preview_request, aws_get_credentials \u2014 STS AssumeRole under the hood); GCP, Azure, and Cloudflare land alongside in the same package as the broker grows.",
|
|
21219
21219
|
type: "module",
|
|
21220
21220
|
bin: {
|
|
21221
21221
|
"cloud-broker": "./dist/index.js"
|
|
@@ -21275,7 +21275,7 @@ if (process.env.AGT_TEAM_SLUG) {
|
|
|
21275
21275
|
var broker = new BrokerClient({
|
|
21276
21276
|
host: AGT_HOST,
|
|
21277
21277
|
agentId: AGT_AGENT_ID,
|
|
21278
|
-
// ENG-4746: thread AGT_RUN_ID through so
|
|
21278
|
+
// ENG-4746: thread AGT_RUN_ID through so aws_request_access can default it.
|
|
21279
21279
|
// Empty string is treated as absent — the broker client only fills runId
|
|
21280
21280
|
// on requestAccess if a non-empty value is provided.
|
|
21281
21281
|
runId: AGT_RUN_ID || void 0,
|
|
@@ -21294,8 +21294,8 @@ var server = new McpServer({
|
|
|
21294
21294
|
version: package_default.version
|
|
21295
21295
|
});
|
|
21296
21296
|
server.tool(
|
|
21297
|
-
"
|
|
21298
|
-
"Return the team's resolved AWS policy ceiling for an account: max_ttl_seconds, allowed_regions, auto_approved_actions, and the action denylist. Call this before
|
|
21297
|
+
"aws_describe_scope",
|
|
21298
|
+
"Return the team's resolved AWS policy ceiling for an account: max_ttl_seconds, allowed_regions, auto_approved_actions, and the action denylist. Call this before aws_request_access if you're not sure what you're allowed to ask for \u2014 it's free, idempotent, and writes nothing.",
|
|
21299
21299
|
describeScopeShape,
|
|
21300
21300
|
async (args) => {
|
|
21301
21301
|
try {
|
|
@@ -21307,7 +21307,7 @@ server.tool(
|
|
|
21307
21307
|
}
|
|
21308
21308
|
);
|
|
21309
21309
|
server.tool(
|
|
21310
|
-
"
|
|
21310
|
+
"aws_preview_request",
|
|
21311
21311
|
'Dry-run a candidate request. Returns one of "auto_approve", "route_to_approver", or "hard_deny" without dispatching anything or writing audit_log. Useful for letting the agent self-tighten its scope before triggering a human approval.',
|
|
21312
21312
|
previewRequestShape,
|
|
21313
21313
|
async (args) => {
|
|
@@ -21320,8 +21320,8 @@ server.tool(
|
|
|
21320
21320
|
}
|
|
21321
21321
|
);
|
|
21322
21322
|
server.tool(
|
|
21323
|
-
"
|
|
21324
|
-
'Request scoped, TTL-bounded AWS credentials for the current task. agent_id and run_id are optional \u2014 the broker fills them from the host MCP env (AGT_AGENT_ID / AGT_RUN_ID). source_context is optional but you SHOULD pass it whenever the request was triggered by an inbound channel message: extract { channel_type, channel_id, thread_ts? } from the `<channel>` tag in the conversation that triggered this. Slack: channel_type="slack", channel_id=tag\'s `channel`, thread_ts=tag\'s `thread_ts`. Telegram: channel_type="telegram", channel_id=tag\'s `chat_id`. Direct-chat: channel_type="direct-chat", channel_id=tag\'s `session_id`. Without source_context the resolution notification dead-ends in your direct-chat instead of threading back to the original conversation. Returns { grant_id, status, secret_ref?, expires_at?, denial_reason?, notification_status?, notification_failure_reason? }. status="active" means credentials are ready, use them now. status="denied" means the request was rejected (denial_reason explains). status="pending" means approval is still outstanding \u2014 DO NOT poll. The broker pushes the resolution to you via direct-chat the moment a human approves or denies, so save the grant_id, return control, and resume when the inbound message arrives. The notification body will include an "Original conversation:" line naming the channel/thread to reply in \u2014 complete the user\'s task there, not in direct-chat. Only check notification_status if you need to flag a setup issue to the user: "sent" means a human was paged; "failed" or "not_attempted" means no human was paged (typically channel_not_found because the approval-bot is not a member of the configured channel) \u2014 quote grant_id + notification_failure_reason and recommend manual escalation.
|
|
21323
|
+
"aws_request_access",
|
|
21324
|
+
'Request scoped, TTL-bounded AWS credentials for the current task. agent_id and run_id are optional \u2014 the broker fills them from the host MCP env (AGT_AGENT_ID / AGT_RUN_ID). source_context is optional but you SHOULD pass it whenever the request was triggered by an inbound channel message: extract { channel_type, channel_id, thread_ts? } from the `<channel>` tag in the conversation that triggered this. Slack: channel_type="slack", channel_id=tag\'s `channel`, thread_ts=tag\'s `thread_ts`. Telegram: channel_type="telegram", channel_id=tag\'s `chat_id`. Direct-chat: channel_type="direct-chat", channel_id=tag\'s `session_id`. Without source_context the resolution notification dead-ends in your direct-chat instead of threading back to the original conversation. Returns { grant_id, status, secret_ref?, expires_at?, denial_reason?, notification_status?, notification_failure_reason? }. status="active" means credentials are ready, use them now. status="denied" means the request was rejected (denial_reason explains). status="pending" means approval is still outstanding \u2014 DO NOT poll. The broker pushes the resolution to you via direct-chat the moment a human approves or denies, so save the grant_id, return control, and resume when the inbound message arrives. The notification body will include an "Original conversation:" line naming the channel/thread to reply in \u2014 complete the user\'s task there, not in direct-chat. Only check notification_status if you need to flag a setup issue to the user: "sent" means a human was paged; "failed" or "not_attempted" means no human was paged (typically channel_not_found because the approval-bot is not a member of the configured channel) \u2014 quote grant_id + notification_failure_reason and recommend manual escalation. aws_poll_grant exists as an escape hatch for explicit re-checks but the autonomous flow does not need it.',
|
|
21325
21325
|
requestAccessShape,
|
|
21326
21326
|
async (args) => {
|
|
21327
21327
|
try {
|
|
@@ -21334,8 +21334,8 @@ server.tool(
|
|
|
21334
21334
|
}
|
|
21335
21335
|
);
|
|
21336
21336
|
server.tool(
|
|
21337
|
-
"
|
|
21338
|
-
"Single-shot status check for a grant. The broker pushes resolution updates to you via direct-chat automatically \u2014 you do NOT need to poll in the normal flow. Use this only as an escape hatch: explicit re-check after a notification, or if you suspect a notification was lost (e.g. you got `
|
|
21337
|
+
"aws_poll_grant",
|
|
21338
|
+
"Single-shot status check for a grant. The broker pushes resolution updates to you via direct-chat automatically \u2014 you do NOT need to poll in the normal flow. Use this only as an escape hatch: explicit re-check after a notification, or if you suspect a notification was lost (e.g. you got `aws_request_access` returning pending more than ~5 minutes ago and have heard nothing). Returns { grant_id, status, secret_ref?, expires_at?, denial_reason? }.",
|
|
21339
21339
|
pollGrantShape,
|
|
21340
21340
|
async (args) => {
|
|
21341
21341
|
try {
|
|
@@ -21347,7 +21347,7 @@ server.tool(
|
|
|
21347
21347
|
}
|
|
21348
21348
|
);
|
|
21349
21349
|
server.tool(
|
|
21350
|
-
"
|
|
21350
|
+
"aws_release_access",
|
|
21351
21351
|
"Voluntarily release a grant before its TTL expires. Idempotent \u2014 safe to call on already-revoked or already-expired grants. Returns { grant_id, status }.",
|
|
21352
21352
|
releaseAccessShape,
|
|
21353
21353
|
async (args) => {
|
|
@@ -21360,8 +21360,8 @@ server.tool(
|
|
|
21360
21360
|
}
|
|
21361
21361
|
);
|
|
21362
21362
|
server.tool(
|
|
21363
|
-
"
|
|
21364
|
-
"Fetch the AWS credentials for an active grant. Call this AFTER
|
|
21363
|
+
"aws_get_credentials",
|
|
21364
|
+
"Fetch the AWS credentials for an active grant. Call this AFTER aws_request_access returns active (auto-approve) OR after the resolution-notification arrives (route_to_approver). Returns { grant_id, expires_at, credentials: { access_key_id, secret_access_key, session_token } }. Use them by prefixing your bash invocation, e.g. `AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_SESSION_TOKEN=... aws ec2 describe-instances`. The grant must still be active and unexpired \u2014 409 if already released, 410 if past expires_at. Safe to call multiple times within the TTL window; the credentials don't change. Call aws_release_access when done.",
|
|
21365
21365
|
getCredentialsShape,
|
|
21366
21366
|
async (args) => {
|
|
21367
21367
|
try {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@integrity-labs/cloud-broker",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Cloud Access Broker — MCP server that mints scoped, TTL-bounded cloud credentials per agent task. v1 ships AWS support (
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Cloud Access Broker — MCP server that mints scoped, TTL-bounded cloud credentials per agent task. v1 ships AWS support (aws_request_access, aws_poll_grant, aws_release_access, aws_describe_scope, aws_preview_request, aws_get_credentials — STS AssumeRole under the hood); GCP, Azure, and Cloudflare land alongside in the same package as the broker grows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cloud-broker": "./dist/index.js"
|