@agent-native/core 0.124.5 → 0.124.6
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/corpus/core/CHANGELOG.md +6 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +28 -3
- package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +28 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +28 -3
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +28 -3
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +28 -3
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +28 -3
- package/package.json +1 -1
- package/src/templates/default/.agents/skills/secrets/SKILL.md +28 -3
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +28 -3
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +28 -3
package/corpus/core/CHANGELOG.md
CHANGED
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.124.
|
|
3
|
+
"version": "0.124.6",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -177,9 +177,34 @@ workspace repo:
|
|
|
177
177
|
npx agent-native doctor --only no-env-credentials
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
## `resolveCredential` sees exactly one organization
|
|
181
|
+
|
|
182
|
+
`resolveCredential(key, { userEmail, orgId })` checks the user scope, then the
|
|
183
|
+
one `orgId` you pass, then the solo workspace. That is the whole search. It is
|
|
184
|
+
correct for a signed-in request, and wrong for two common cases:
|
|
185
|
+
|
|
186
|
+
- **The caller has no organization.** A cron, a scheduled job, or any CLI run
|
|
187
|
+
without a real member identity resolves no `orgId`, so only the user and solo
|
|
188
|
+
scopes are ever consulted — and a shared key is in neither.
|
|
189
|
+
- **The key was synced under a different organization.** `app_secrets` has no
|
|
190
|
+
scope visible to every org (`readAppSecret` is strict equality on
|
|
191
|
+
`(scope, scope_id, key)`), so a key the vault UI advertises as available to
|
|
192
|
+
every app is unreadable from any org except the one that ran the sync.
|
|
193
|
+
|
|
194
|
+
Both produce the same misleading "not set" that the split brain above produces,
|
|
195
|
+
which is why swapping `process.env` for `resolveCredential` can look like a fix
|
|
196
|
+
and change nothing. A workspace app should read shared keys through a resolver
|
|
197
|
+
that also sweeps the caller's other memberships and a designated vault org —
|
|
198
|
+
see `resolveConnectorSecret` and `AGENT_VAULT_ORG_ID` in the builder-workspace
|
|
199
|
+
repo for the shape, including the boot-time assertion that the deployment really
|
|
200
|
+
is single-tenant before a non-membership-gated fallback is safe.
|
|
201
|
+
|
|
202
|
+
**The doctor guard does not catch this second form** — it looks for
|
|
203
|
+
`process.env` reads, and `resolveCredential` is not one. Grep for
|
|
204
|
+
`resolveCredential` yourself and confirm each call sits somewhere a single-org
|
|
205
|
+
lookup is genuinely the right question. Findings that pair it with a
|
|
206
|
+
`?? process.env.KEY` fallback are the sanctioned deploy-level escape hatch; the
|
|
207
|
+
bugs are calls whose value can only live in another org's vault.
|
|
183
208
|
|
|
184
209
|
## HTTP routes
|
|
185
210
|
|
|
@@ -177,9 +177,34 @@ workspace repo:
|
|
|
177
177
|
npx agent-native doctor --only no-env-credentials
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
## `resolveCredential` sees exactly one organization
|
|
181
|
+
|
|
182
|
+
`resolveCredential(key, { userEmail, orgId })` checks the user scope, then the
|
|
183
|
+
one `orgId` you pass, then the solo workspace. That is the whole search. It is
|
|
184
|
+
correct for a signed-in request, and wrong for two common cases:
|
|
185
|
+
|
|
186
|
+
- **The caller has no organization.** A cron, a scheduled job, or any CLI run
|
|
187
|
+
without a real member identity resolves no `orgId`, so only the user and solo
|
|
188
|
+
scopes are ever consulted — and a shared key is in neither.
|
|
189
|
+
- **The key was synced under a different organization.** `app_secrets` has no
|
|
190
|
+
scope visible to every org (`readAppSecret` is strict equality on
|
|
191
|
+
`(scope, scope_id, key)`), so a key the vault UI advertises as available to
|
|
192
|
+
every app is unreadable from any org except the one that ran the sync.
|
|
193
|
+
|
|
194
|
+
Both produce the same misleading "not set" that the split brain above produces,
|
|
195
|
+
which is why swapping `process.env` for `resolveCredential` can look like a fix
|
|
196
|
+
and change nothing. A workspace app should read shared keys through a resolver
|
|
197
|
+
that also sweeps the caller's other memberships and a designated vault org —
|
|
198
|
+
see `resolveConnectorSecret` and `AGENT_VAULT_ORG_ID` in the builder-workspace
|
|
199
|
+
repo for the shape, including the boot-time assertion that the deployment really
|
|
200
|
+
is single-tenant before a non-membership-gated fallback is safe.
|
|
201
|
+
|
|
202
|
+
**The doctor guard does not catch this second form** — it looks for
|
|
203
|
+
`process.env` reads, and `resolveCredential` is not one. Grep for
|
|
204
|
+
`resolveCredential` yourself and confirm each call sits somewhere a single-org
|
|
205
|
+
lookup is genuinely the right question. Findings that pair it with a
|
|
206
|
+
`?? process.env.KEY` fallback are the sanctioned deploy-level escape hatch; the
|
|
207
|
+
bugs are calls whose value can only live in another org's vault.
|
|
183
208
|
|
|
184
209
|
## HTTP routes
|
|
185
210
|
|
|
@@ -177,9 +177,34 @@ workspace repo:
|
|
|
177
177
|
npx agent-native doctor --only no-env-credentials
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
## `resolveCredential` sees exactly one organization
|
|
181
|
+
|
|
182
|
+
`resolveCredential(key, { userEmail, orgId })` checks the user scope, then the
|
|
183
|
+
one `orgId` you pass, then the solo workspace. That is the whole search. It is
|
|
184
|
+
correct for a signed-in request, and wrong for two common cases:
|
|
185
|
+
|
|
186
|
+
- **The caller has no organization.** A cron, a scheduled job, or any CLI run
|
|
187
|
+
without a real member identity resolves no `orgId`, so only the user and solo
|
|
188
|
+
scopes are ever consulted — and a shared key is in neither.
|
|
189
|
+
- **The key was synced under a different organization.** `app_secrets` has no
|
|
190
|
+
scope visible to every org (`readAppSecret` is strict equality on
|
|
191
|
+
`(scope, scope_id, key)`), so a key the vault UI advertises as available to
|
|
192
|
+
every app is unreadable from any org except the one that ran the sync.
|
|
193
|
+
|
|
194
|
+
Both produce the same misleading "not set" that the split brain above produces,
|
|
195
|
+
which is why swapping `process.env` for `resolveCredential` can look like a fix
|
|
196
|
+
and change nothing. A workspace app should read shared keys through a resolver
|
|
197
|
+
that also sweeps the caller's other memberships and a designated vault org —
|
|
198
|
+
see `resolveConnectorSecret` and `AGENT_VAULT_ORG_ID` in the builder-workspace
|
|
199
|
+
repo for the shape, including the boot-time assertion that the deployment really
|
|
200
|
+
is single-tenant before a non-membership-gated fallback is safe.
|
|
201
|
+
|
|
202
|
+
**The doctor guard does not catch this second form** — it looks for
|
|
203
|
+
`process.env` reads, and `resolveCredential` is not one. Grep for
|
|
204
|
+
`resolveCredential` yourself and confirm each call sits somewhere a single-org
|
|
205
|
+
lookup is genuinely the right question. Findings that pair it with a
|
|
206
|
+
`?? process.env.KEY` fallback are the sanctioned deploy-level escape hatch; the
|
|
207
|
+
bugs are calls whose value can only live in another org's vault.
|
|
183
208
|
|
|
184
209
|
## HTTP routes
|
|
185
210
|
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -41,9 +41,9 @@ export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import
|
|
|
41
41
|
* Body: { text: string, fieldName?: string, requestSource?: string }
|
|
42
42
|
*/
|
|
43
43
|
export declare const postCollabText: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
44
|
+
text?: undefined;
|
|
44
45
|
ok?: undefined;
|
|
45
46
|
error: string;
|
|
46
|
-
text?: undefined;
|
|
47
47
|
} | {
|
|
48
48
|
error?: undefined;
|
|
49
49
|
ok: boolean;
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
|
|
14
14
|
*/
|
|
15
15
|
export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
error: string;
|
|
17
16
|
ok?: undefined;
|
|
17
|
+
error: string;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
|
@@ -17,12 +17,12 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
17
17
|
id?: undefined;
|
|
18
18
|
provider?: undefined;
|
|
19
19
|
} | {
|
|
20
|
+
error?: undefined;
|
|
20
21
|
configured?: undefined;
|
|
21
22
|
connectPath?: undefined;
|
|
22
23
|
url: string;
|
|
23
24
|
id: string;
|
|
24
25
|
provider: string;
|
|
25
|
-
error?: undefined;
|
|
26
26
|
}>;
|
|
27
27
|
export default _default;
|
|
28
28
|
//# sourceMappingURL=upload-image.d.ts.map
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
14
14
|
count: number;
|
|
15
15
|
updated?: undefined;
|
|
16
|
-
ok?: undefined;
|
|
17
16
|
error?: undefined;
|
|
17
|
+
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
19
|
count?: undefined;
|
|
20
20
|
updated: number;
|
|
21
|
-
ok?: undefined;
|
|
22
21
|
error?: undefined;
|
|
22
|
+
ok?: undefined;
|
|
23
23
|
} | {
|
|
24
24
|
count?: undefined;
|
|
25
25
|
updated?: undefined;
|
|
@@ -28,7 +28,7 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
|
|
|
28
28
|
} | {
|
|
29
29
|
count?: undefined;
|
|
30
30
|
updated?: undefined;
|
|
31
|
-
ok: boolean;
|
|
32
31
|
error?: undefined;
|
|
32
|
+
ok: boolean;
|
|
33
33
|
}>>;
|
|
34
34
|
//# sourceMappingURL=routes.d.ts.map
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -34,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
|
|
|
34
34
|
/** POST /_agent-native/secrets/:key — write a secret. */
|
|
35
35
|
export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
36
36
|
error: string;
|
|
37
|
-
status?: undefined;
|
|
38
37
|
ok?: undefined;
|
|
38
|
+
status?: undefined;
|
|
39
39
|
} | {
|
|
40
|
+
error?: undefined;
|
|
40
41
|
ok: boolean;
|
|
41
42
|
status: string;
|
|
42
|
-
error?: undefined;
|
|
43
43
|
} | {
|
|
44
|
+
ok?: undefined;
|
|
44
45
|
error: string;
|
|
45
46
|
removed?: undefined;
|
|
46
|
-
ok?: undefined;
|
|
47
47
|
} | {
|
|
48
|
+
error?: undefined;
|
|
48
49
|
ok: boolean;
|
|
49
50
|
removed: boolean;
|
|
50
|
-
error?: undefined;
|
|
51
51
|
}>>;
|
|
52
52
|
/**
|
|
53
53
|
* POST /_agent-native/secrets/:key/test — re-run the validator against the
|
|
54
54
|
* current stored value without changing anything. Useful for the "Test" button.
|
|
55
55
|
*/
|
|
56
56
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
57
|
+
ok?: undefined;
|
|
57
58
|
error: string;
|
|
58
59
|
note?: undefined;
|
|
59
|
-
ok?: undefined;
|
|
60
60
|
} | {
|
|
61
|
+
error?: undefined;
|
|
61
62
|
ok: boolean;
|
|
62
63
|
note?: undefined;
|
|
63
|
-
error?: undefined;
|
|
64
64
|
} | {
|
|
65
|
+
error?: undefined;
|
|
65
66
|
ok: boolean;
|
|
66
67
|
note: string;
|
|
67
|
-
error?: undefined;
|
|
68
68
|
} | {
|
|
69
69
|
note?: undefined;
|
|
70
70
|
ok: boolean;
|
|
@@ -95,12 +95,12 @@ export interface AdHocSecretPayload {
|
|
|
95
95
|
export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
|
|
96
96
|
error: string;
|
|
97
97
|
} | {
|
|
98
|
+
error?: undefined;
|
|
98
99
|
ok: boolean;
|
|
99
100
|
key: string;
|
|
100
|
-
error?: undefined;
|
|
101
101
|
} | {
|
|
102
|
+
error?: undefined;
|
|
102
103
|
ok: boolean;
|
|
103
104
|
removed: boolean;
|
|
104
|
-
error?: undefined;
|
|
105
105
|
}>>;
|
|
106
106
|
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -26,9 +26,9 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
expiresAt?: undefined;
|
|
27
27
|
ttlSeconds?: undefined;
|
|
28
28
|
} | {
|
|
29
|
-
error?: undefined;
|
|
30
29
|
token: string;
|
|
31
30
|
expiresAt: string;
|
|
32
31
|
ttlSeconds: number;
|
|
32
|
+
error?: undefined;
|
|
33
33
|
}>>;
|
|
34
34
|
//# sourceMappingURL=realtime-token.d.ts.map
|
|
@@ -177,9 +177,34 @@ workspace repo:
|
|
|
177
177
|
npx agent-native doctor --only no-env-credentials
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
## `resolveCredential` sees exactly one organization
|
|
181
|
+
|
|
182
|
+
`resolveCredential(key, { userEmail, orgId })` checks the user scope, then the
|
|
183
|
+
one `orgId` you pass, then the solo workspace. That is the whole search. It is
|
|
184
|
+
correct for a signed-in request, and wrong for two common cases:
|
|
185
|
+
|
|
186
|
+
- **The caller has no organization.** A cron, a scheduled job, or any CLI run
|
|
187
|
+
without a real member identity resolves no `orgId`, so only the user and solo
|
|
188
|
+
scopes are ever consulted — and a shared key is in neither.
|
|
189
|
+
- **The key was synced under a different organization.** `app_secrets` has no
|
|
190
|
+
scope visible to every org (`readAppSecret` is strict equality on
|
|
191
|
+
`(scope, scope_id, key)`), so a key the vault UI advertises as available to
|
|
192
|
+
every app is unreadable from any org except the one that ran the sync.
|
|
193
|
+
|
|
194
|
+
Both produce the same misleading "not set" that the split brain above produces,
|
|
195
|
+
which is why swapping `process.env` for `resolveCredential` can look like a fix
|
|
196
|
+
and change nothing. A workspace app should read shared keys through a resolver
|
|
197
|
+
that also sweeps the caller's other memberships and a designated vault org —
|
|
198
|
+
see `resolveConnectorSecret` and `AGENT_VAULT_ORG_ID` in the builder-workspace
|
|
199
|
+
repo for the shape, including the boot-time assertion that the deployment really
|
|
200
|
+
is single-tenant before a non-membership-gated fallback is safe.
|
|
201
|
+
|
|
202
|
+
**The doctor guard does not catch this second form** — it looks for
|
|
203
|
+
`process.env` reads, and `resolveCredential` is not one. Grep for
|
|
204
|
+
`resolveCredential` yourself and confirm each call sits somewhere a single-org
|
|
205
|
+
lookup is genuinely the right question. Findings that pair it with a
|
|
206
|
+
`?? process.env.KEY` fallback are the sanctioned deploy-level escape hatch; the
|
|
207
|
+
bugs are calls whose value can only live in another org's vault.
|
|
183
208
|
|
|
184
209
|
## HTTP routes
|
|
185
210
|
|
|
@@ -177,9 +177,34 @@ workspace repo:
|
|
|
177
177
|
npx agent-native doctor --only no-env-credentials
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
## `resolveCredential` sees exactly one organization
|
|
181
|
+
|
|
182
|
+
`resolveCredential(key, { userEmail, orgId })` checks the user scope, then the
|
|
183
|
+
one `orgId` you pass, then the solo workspace. That is the whole search. It is
|
|
184
|
+
correct for a signed-in request, and wrong for two common cases:
|
|
185
|
+
|
|
186
|
+
- **The caller has no organization.** A cron, a scheduled job, or any CLI run
|
|
187
|
+
without a real member identity resolves no `orgId`, so only the user and solo
|
|
188
|
+
scopes are ever consulted — and a shared key is in neither.
|
|
189
|
+
- **The key was synced under a different organization.** `app_secrets` has no
|
|
190
|
+
scope visible to every org (`readAppSecret` is strict equality on
|
|
191
|
+
`(scope, scope_id, key)`), so a key the vault UI advertises as available to
|
|
192
|
+
every app is unreadable from any org except the one that ran the sync.
|
|
193
|
+
|
|
194
|
+
Both produce the same misleading "not set" that the split brain above produces,
|
|
195
|
+
which is why swapping `process.env` for `resolveCredential` can look like a fix
|
|
196
|
+
and change nothing. A workspace app should read shared keys through a resolver
|
|
197
|
+
that also sweeps the caller's other memberships and a designated vault org —
|
|
198
|
+
see `resolveConnectorSecret` and `AGENT_VAULT_ORG_ID` in the builder-workspace
|
|
199
|
+
repo for the shape, including the boot-time assertion that the deployment really
|
|
200
|
+
is single-tenant before a non-membership-gated fallback is safe.
|
|
201
|
+
|
|
202
|
+
**The doctor guard does not catch this second form** — it looks for
|
|
203
|
+
`process.env` reads, and `resolveCredential` is not one. Grep for
|
|
204
|
+
`resolveCredential` yourself and confirm each call sits somewhere a single-org
|
|
205
|
+
lookup is genuinely the right question. Findings that pair it with a
|
|
206
|
+
`?? process.env.KEY` fallback are the sanctioned deploy-level escape hatch; the
|
|
207
|
+
bugs are calls whose value can only live in another org's vault.
|
|
183
208
|
|
|
184
209
|
## HTTP routes
|
|
185
210
|
|
|
@@ -177,9 +177,34 @@ workspace repo:
|
|
|
177
177
|
npx agent-native doctor --only no-env-credentials
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
## `resolveCredential` sees exactly one organization
|
|
181
|
+
|
|
182
|
+
`resolveCredential(key, { userEmail, orgId })` checks the user scope, then the
|
|
183
|
+
one `orgId` you pass, then the solo workspace. That is the whole search. It is
|
|
184
|
+
correct for a signed-in request, and wrong for two common cases:
|
|
185
|
+
|
|
186
|
+
- **The caller has no organization.** A cron, a scheduled job, or any CLI run
|
|
187
|
+
without a real member identity resolves no `orgId`, so only the user and solo
|
|
188
|
+
scopes are ever consulted — and a shared key is in neither.
|
|
189
|
+
- **The key was synced under a different organization.** `app_secrets` has no
|
|
190
|
+
scope visible to every org (`readAppSecret` is strict equality on
|
|
191
|
+
`(scope, scope_id, key)`), so a key the vault UI advertises as available to
|
|
192
|
+
every app is unreadable from any org except the one that ran the sync.
|
|
193
|
+
|
|
194
|
+
Both produce the same misleading "not set" that the split brain above produces,
|
|
195
|
+
which is why swapping `process.env` for `resolveCredential` can look like a fix
|
|
196
|
+
and change nothing. A workspace app should read shared keys through a resolver
|
|
197
|
+
that also sweeps the caller's other memberships and a designated vault org —
|
|
198
|
+
see `resolveConnectorSecret` and `AGENT_VAULT_ORG_ID` in the builder-workspace
|
|
199
|
+
repo for the shape, including the boot-time assertion that the deployment really
|
|
200
|
+
is single-tenant before a non-membership-gated fallback is safe.
|
|
201
|
+
|
|
202
|
+
**The doctor guard does not catch this second form** — it looks for
|
|
203
|
+
`process.env` reads, and `resolveCredential` is not one. Grep for
|
|
204
|
+
`resolveCredential` yourself and confirm each call sits somewhere a single-org
|
|
205
|
+
lookup is genuinely the right question. Findings that pair it with a
|
|
206
|
+
`?? process.env.KEY` fallback are the sanctioned deploy-level escape hatch; the
|
|
207
|
+
bugs are calls whose value can only live in another org's vault.
|
|
183
208
|
|
|
184
209
|
## HTTP routes
|
|
185
210
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.124.
|
|
3
|
+
"version": "0.124.6",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -177,9 +177,34 @@ workspace repo:
|
|
|
177
177
|
npx agent-native doctor --only no-env-credentials
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
## `resolveCredential` sees exactly one organization
|
|
181
|
+
|
|
182
|
+
`resolveCredential(key, { userEmail, orgId })` checks the user scope, then the
|
|
183
|
+
one `orgId` you pass, then the solo workspace. That is the whole search. It is
|
|
184
|
+
correct for a signed-in request, and wrong for two common cases:
|
|
185
|
+
|
|
186
|
+
- **The caller has no organization.** A cron, a scheduled job, or any CLI run
|
|
187
|
+
without a real member identity resolves no `orgId`, so only the user and solo
|
|
188
|
+
scopes are ever consulted — and a shared key is in neither.
|
|
189
|
+
- **The key was synced under a different organization.** `app_secrets` has no
|
|
190
|
+
scope visible to every org (`readAppSecret` is strict equality on
|
|
191
|
+
`(scope, scope_id, key)`), so a key the vault UI advertises as available to
|
|
192
|
+
every app is unreadable from any org except the one that ran the sync.
|
|
193
|
+
|
|
194
|
+
Both produce the same misleading "not set" that the split brain above produces,
|
|
195
|
+
which is why swapping `process.env` for `resolveCredential` can look like a fix
|
|
196
|
+
and change nothing. A workspace app should read shared keys through a resolver
|
|
197
|
+
that also sweeps the caller's other memberships and a designated vault org —
|
|
198
|
+
see `resolveConnectorSecret` and `AGENT_VAULT_ORG_ID` in the builder-workspace
|
|
199
|
+
repo for the shape, including the boot-time assertion that the deployment really
|
|
200
|
+
is single-tenant before a non-membership-gated fallback is safe.
|
|
201
|
+
|
|
202
|
+
**The doctor guard does not catch this second form** — it looks for
|
|
203
|
+
`process.env` reads, and `resolveCredential` is not one. Grep for
|
|
204
|
+
`resolveCredential` yourself and confirm each call sits somewhere a single-org
|
|
205
|
+
lookup is genuinely the right question. Findings that pair it with a
|
|
206
|
+
`?? process.env.KEY` fallback are the sanctioned deploy-level escape hatch; the
|
|
207
|
+
bugs are calls whose value can only live in another org's vault.
|
|
183
208
|
|
|
184
209
|
## HTTP routes
|
|
185
210
|
|
|
@@ -177,9 +177,34 @@ workspace repo:
|
|
|
177
177
|
npx agent-native doctor --only no-env-credentials
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
## `resolveCredential` sees exactly one organization
|
|
181
|
+
|
|
182
|
+
`resolveCredential(key, { userEmail, orgId })` checks the user scope, then the
|
|
183
|
+
one `orgId` you pass, then the solo workspace. That is the whole search. It is
|
|
184
|
+
correct for a signed-in request, and wrong for two common cases:
|
|
185
|
+
|
|
186
|
+
- **The caller has no organization.** A cron, a scheduled job, or any CLI run
|
|
187
|
+
without a real member identity resolves no `orgId`, so only the user and solo
|
|
188
|
+
scopes are ever consulted — and a shared key is in neither.
|
|
189
|
+
- **The key was synced under a different organization.** `app_secrets` has no
|
|
190
|
+
scope visible to every org (`readAppSecret` is strict equality on
|
|
191
|
+
`(scope, scope_id, key)`), so a key the vault UI advertises as available to
|
|
192
|
+
every app is unreadable from any org except the one that ran the sync.
|
|
193
|
+
|
|
194
|
+
Both produce the same misleading "not set" that the split brain above produces,
|
|
195
|
+
which is why swapping `process.env` for `resolveCredential` can look like a fix
|
|
196
|
+
and change nothing. A workspace app should read shared keys through a resolver
|
|
197
|
+
that also sweeps the caller's other memberships and a designated vault org —
|
|
198
|
+
see `resolveConnectorSecret` and `AGENT_VAULT_ORG_ID` in the builder-workspace
|
|
199
|
+
repo for the shape, including the boot-time assertion that the deployment really
|
|
200
|
+
is single-tenant before a non-membership-gated fallback is safe.
|
|
201
|
+
|
|
202
|
+
**The doctor guard does not catch this second form** — it looks for
|
|
203
|
+
`process.env` reads, and `resolveCredential` is not one. Grep for
|
|
204
|
+
`resolveCredential` yourself and confirm each call sits somewhere a single-org
|
|
205
|
+
lookup is genuinely the right question. Findings that pair it with a
|
|
206
|
+
`?? process.env.KEY` fallback are the sanctioned deploy-level escape hatch; the
|
|
207
|
+
bugs are calls whose value can only live in another org's vault.
|
|
183
208
|
|
|
184
209
|
## HTTP routes
|
|
185
210
|
|
|
@@ -177,9 +177,34 @@ workspace repo:
|
|
|
177
177
|
npx agent-native doctor --only no-env-credentials
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
## `resolveCredential` sees exactly one organization
|
|
181
|
+
|
|
182
|
+
`resolveCredential(key, { userEmail, orgId })` checks the user scope, then the
|
|
183
|
+
one `orgId` you pass, then the solo workspace. That is the whole search. It is
|
|
184
|
+
correct for a signed-in request, and wrong for two common cases:
|
|
185
|
+
|
|
186
|
+
- **The caller has no organization.** A cron, a scheduled job, or any CLI run
|
|
187
|
+
without a real member identity resolves no `orgId`, so only the user and solo
|
|
188
|
+
scopes are ever consulted — and a shared key is in neither.
|
|
189
|
+
- **The key was synced under a different organization.** `app_secrets` has no
|
|
190
|
+
scope visible to every org (`readAppSecret` is strict equality on
|
|
191
|
+
`(scope, scope_id, key)`), so a key the vault UI advertises as available to
|
|
192
|
+
every app is unreadable from any org except the one that ran the sync.
|
|
193
|
+
|
|
194
|
+
Both produce the same misleading "not set" that the split brain above produces,
|
|
195
|
+
which is why swapping `process.env` for `resolveCredential` can look like a fix
|
|
196
|
+
and change nothing. A workspace app should read shared keys through a resolver
|
|
197
|
+
that also sweeps the caller's other memberships and a designated vault org —
|
|
198
|
+
see `resolveConnectorSecret` and `AGENT_VAULT_ORG_ID` in the builder-workspace
|
|
199
|
+
repo for the shape, including the boot-time assertion that the deployment really
|
|
200
|
+
is single-tenant before a non-membership-gated fallback is safe.
|
|
201
|
+
|
|
202
|
+
**The doctor guard does not catch this second form** — it looks for
|
|
203
|
+
`process.env` reads, and `resolveCredential` is not one. Grep for
|
|
204
|
+
`resolveCredential` yourself and confirm each call sits somewhere a single-org
|
|
205
|
+
lookup is genuinely the right question. Findings that pair it with a
|
|
206
|
+
`?? process.env.KEY` fallback are the sanctioned deploy-level escape hatch; the
|
|
207
|
+
bugs are calls whose value can only live in another org's vault.
|
|
183
208
|
|
|
184
209
|
## HTTP routes
|
|
185
210
|
|