@oxy.so/core 1.7.3 → 1.8.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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/inference/OxyInferenceClient.js +8 -3
- package/dist/cjs/mixins/OxyServices.auth.js +9 -6
- package/dist/cjs/mixins/OxyServices.utility.js +23 -6
- package/dist/cjs/package.json +9 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/inference/OxyInferenceClient.js +8 -3
- package/dist/esm/mixins/OxyServices.auth.js +9 -6
- package/dist/esm/mixins/OxyServices.utility.js +23 -6
- package/dist/esm/package.json +9 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/inference/OxyInferenceClient.d.ts +15 -4
- package/dist/types/mixins/OxyServices.auth.d.ts +7 -4
- package/dist/types/mixins/OxyServices.utility.d.ts +8 -0
- package/dist/types/server/auth.d.ts +2 -0
- package/package.json +3 -13
- package/src/inference/OxyInferenceClient.ts +15 -3
- package/src/inference/__tests__/OxyInferenceClient.test.ts +17 -0
- package/src/mixins/OxyServices.auth.ts +9 -6
- package/src/mixins/OxyServices.utility.ts +33 -6
- package/src/mixins/__tests__/serviceAuth.test.ts +57 -0
- package/src/server/auth.ts +2 -0
|
@@ -145,9 +145,14 @@ class OxyInferenceClient {
|
|
|
145
145
|
* both see the PUBLIC catalogue; only an internal/system application's
|
|
146
146
|
* service token sees internal-only routes.
|
|
147
147
|
*
|
|
148
|
-
* **`[]` is a normal answer
|
|
149
|
-
*
|
|
150
|
-
*
|
|
148
|
+
* **`[]` is a normal answer**: a route is not publicly exposed until
|
|
149
|
+
* somebody has reviewed the right to resell it. An official application's
|
|
150
|
+
* credential also sees the internal catalogue Oxy keeps in step with
|
|
151
|
+
* Kaana automatically.
|
|
152
|
+
*
|
|
153
|
+
* Each entry's `capabilities.reasoningEfforts` lists the efforts a request
|
|
154
|
+
* may name in `reasoning.effort` (empty: none), and `releasedAt`, when
|
|
155
|
+
* present, is the date the upstream provider published the model.
|
|
151
156
|
*/
|
|
152
157
|
async listModels(options = {}) {
|
|
153
158
|
const body = await __classPrivateFieldGet(this, _OxyInferenceClient_instances, "m", _OxyInferenceClient_request).call(this, 'GET', '/v1/models', { ...(options.signal === undefined ? {} : { signal: options.signal }) });
|
|
@@ -299,10 +299,13 @@ function OxyServicesAuthMixin(Base) {
|
|
|
299
299
|
/**
|
|
300
300
|
* Whether this process can prove what it is (ADR 0026).
|
|
301
301
|
*
|
|
302
|
-
*
|
|
303
|
-
* and browser bundlers, and the signer only for
|
|
304
|
-
* Node guard avoids calling attestation on clients;
|
|
305
|
-
* keeps node:crypto out of their bundle graphs (a guard
|
|
302
|
+
* `#workload-identity` (package.json `imports`) selects a client
|
|
303
|
+
* implementation for native and browser bundlers, and the signer only for
|
|
304
|
+
* Node hosts. The runtime Node guard avoids calling attestation on clients;
|
|
305
|
+
* the module boundary keeps node:crypto out of their bundle graphs (a guard
|
|
306
|
+
* alone cannot). It is a package import, not a self-reference to an export
|
|
307
|
+
* subpath: a self-reference only resolves where `@oxy.so/core` is reachable
|
|
308
|
+
* through `node_modules`, which bundlers inside this workspace are not.
|
|
306
309
|
*
|
|
307
310
|
* @internal
|
|
308
311
|
*/
|
|
@@ -310,7 +313,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
310
313
|
if (typeof process === 'undefined' || !process.versions?.node)
|
|
311
314
|
return false;
|
|
312
315
|
try {
|
|
313
|
-
const { canAttestWorkloadIdentity } = await Promise.resolve().then(() => __importStar(require('
|
|
316
|
+
const { canAttestWorkloadIdentity } = await Promise.resolve().then(() => __importStar(require('#workload-identity')));
|
|
314
317
|
return canAttestWorkloadIdentity();
|
|
315
318
|
}
|
|
316
319
|
catch {
|
|
@@ -338,7 +341,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
338
341
|
return entry.token;
|
|
339
342
|
if (entry?.pending)
|
|
340
343
|
return entry.pending;
|
|
341
|
-
const { requestWorkloadServiceToken } = await Promise.resolve().then(() => __importStar(require('
|
|
344
|
+
const { requestWorkloadServiceToken } = await Promise.resolve().then(() => __importStar(require('#workload-identity')));
|
|
342
345
|
const seeded = entry ?? {
|
|
343
346
|
token: '',
|
|
344
347
|
expiresAt: 0,
|
|
@@ -496,6 +496,7 @@ function OxyServicesUtilityMixin(Base) {
|
|
|
496
496
|
return onError(error);
|
|
497
497
|
return res.status(401).json(error);
|
|
498
498
|
}
|
|
499
|
+
const tier = decoded.tier === 'internal' ? 'internal' : 'external';
|
|
499
500
|
// Read delegated user ID from header
|
|
500
501
|
const oxyUserIdRaw = req.headers['x-oxy-user-id'];
|
|
501
502
|
const oxyUserId = isExactNonEmptyServiceClaim(oxyUserIdRaw) ? oxyUserIdRaw : null;
|
|
@@ -516,12 +517,21 @@ function OxyServicesUtilityMixin(Base) {
|
|
|
516
517
|
return onError(error);
|
|
517
518
|
return res.status(401).json(error);
|
|
518
519
|
}
|
|
519
|
-
//
|
|
520
|
-
//
|
|
521
|
-
//
|
|
522
|
-
//
|
|
523
|
-
|
|
524
|
-
|
|
520
|
+
// One of Oxy's own applications acts for a user without a grant:
|
|
521
|
+
// inside the ecosystem that is trust, not consent. It still acts
|
|
522
|
+
// with the USER's authority only — what that user may do is for the
|
|
523
|
+
// receiving service to check.
|
|
524
|
+
if (oxyUserId && tier === 'internal') {
|
|
525
|
+
req.userId = oxyUserId;
|
|
526
|
+
req.user = { id: oxyUserId };
|
|
527
|
+
req.serviceActingAs = { userId: oxyUserId, scopes: [] };
|
|
528
|
+
}
|
|
529
|
+
else if (oxyUserId) {
|
|
530
|
+
// C3: an EXTERNAL service may only act as a user when an explicit
|
|
531
|
+
// ServiceActingAs grant exists for that (appId, userId) pair.
|
|
532
|
+
// Without the grant we MUST refuse — silently attaching
|
|
533
|
+
// `req.userId = oxyUserId` would let any service impersonate
|
|
534
|
+
// any user simply by setting the header.
|
|
525
535
|
const grant = await oxyInstance.verifyServiceActingAs(appId, oxyUserId);
|
|
526
536
|
if (!grant || !grant.authorized) {
|
|
527
537
|
logger_1.logger.warn('[oxy.auth] Service token rejected — no delegation grant', {
|
|
@@ -572,6 +582,7 @@ function OxyServicesUtilityMixin(Base) {
|
|
|
572
582
|
ownerAccountId,
|
|
573
583
|
scopes: Array.isArray(decoded.scopes) ? decoded.scopes : [],
|
|
574
584
|
environment,
|
|
585
|
+
tier,
|
|
575
586
|
};
|
|
576
587
|
if (debug) {
|
|
577
588
|
logger_1.logger.debug(`[oxy.auth] Service token OK app=${decoded.appName} delegateUser=${oxyUserId || '(none)'}`, {
|
|
@@ -1004,6 +1015,12 @@ function OxyServicesUtilityMixin(Base) {
|
|
|
1004
1015
|
});
|
|
1005
1016
|
return;
|
|
1006
1017
|
}
|
|
1018
|
+
// Oxy's own applications are trusted app to app; scopes are the
|
|
1019
|
+
// external lane.
|
|
1020
|
+
if (req.serviceApp.tier === 'internal') {
|
|
1021
|
+
next();
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1007
1024
|
const appHasScope = appScopes.includes(scope);
|
|
1008
1025
|
const delegationHasScope = delegatedScopes.includes(scope);
|
|
1009
1026
|
const hasRequiredScope = req.serviceActingAs
|
package/dist/cjs/package.json
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"type": "commonjs"
|
|
2
|
+
"type": "commonjs",
|
|
3
|
+
"imports": {
|
|
4
|
+
"#workload-identity": {
|
|
5
|
+
"react-native": "./server/workloadIdentity.client.js",
|
|
6
|
+
"browser": "./server/workloadIdentity.client.js",
|
|
7
|
+
"node": "./server/workloadIdentity.js",
|
|
8
|
+
"default": "./server/workloadIdentity.client.js"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
3
11
|
}
|