@canopy-io/node 0.9.0 → 0.10.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/CHANGELOG.md +10 -0
- package/README.md +6 -2
- package/dist/index.cjs +21 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +21 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @canopy-io/node
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f2ee649: `LocalAuthorizer` is held to Canopy's own authorization rules. Its suite replays the conformance vectors Canopy publishes at `/conformance/authorization.json`, the same cases Canopy's API suite replays end to end, and `npm run generate` keeps the copy in step with the published one.
|
|
8
|
+
|
|
9
|
+
The grant roots (`GET /api/v1/identities/:id/grants`) and the hierarchy's parent edges (`GET /api/v1/nodes/parents`) now carry the `model_version` of the authorization model they describe. `LocalAuthorizer` refuses a version it does not know with `CanopyAuthorizerError` (`authorizer.model_version_unknown`), which `authorizationErrorStatus` and the NestJS guard answer as a `500` misconfiguration, rather than walking rows whose meaning has changed. It knows version 1. This release requires a Canopy that sends `model_version`; against one that does not, every check is refused, so upgrade after the API has it.
|
|
10
|
+
|
|
11
|
+
`@canopy-io/nestjs` picks up the new authorizer; its own options and behaviour are unchanged.
|
|
12
|
+
|
|
3
13
|
## 0.9.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -278,8 +278,12 @@ instances behind a load balancer, each keeps its own cache until its TTL runs
|
|
|
278
278
|
out or it is told to invalidate too.
|
|
279
279
|
|
|
280
280
|
A failed check (Canopy unreachable, a credential that cannot read the
|
|
281
|
-
hierarchy, an identity not in the Environment
|
|
282
|
-
|
|
281
|
+
hierarchy, an identity not in the Environment, or a Canopy serving an
|
|
282
|
+
authorization model this version does not know) throws rather than answering
|
|
283
|
+
`false`. The grant roots and the hierarchy each carry the `model_version` of
|
|
284
|
+
the rules they describe; an unknown one is refused with `CanopyAuthorizerError`
|
|
285
|
+
(`authorizer.model_version_unknown`) instead of being walked as if the rules
|
|
286
|
+
had not changed, and upgrading the package is the fix. `authorizationErrorStatus` turns the error into the response to send:
|
|
283
287
|
`503` when Canopy did not answer, `500` for a misconfiguration no retry fixes,
|
|
284
288
|
`403` for an identity Canopy does not know. The NestJS guard uses the same
|
|
285
289
|
mapping.
|
package/dist/index.cjs
CHANGED
|
@@ -1155,6 +1155,16 @@ var MAX_WALK_DEPTH = 256;
|
|
|
1155
1155
|
var PAGE_SIZE = 100;
|
|
1156
1156
|
var MAX_PAGES = 1e4;
|
|
1157
1157
|
var MAX_TREE_WALKS = 3;
|
|
1158
|
+
var KNOWN_MODEL_VERSIONS = /* @__PURE__ */ new Set([1]);
|
|
1159
|
+
function understood(page, path) {
|
|
1160
|
+
if (!KNOWN_MODEL_VERSIONS.has(page.model_version)) {
|
|
1161
|
+
throw new CanopyAuthorizerError(
|
|
1162
|
+
"authorizer.model_version_unknown",
|
|
1163
|
+
`${path} describes authorization model version ${page.model_version}, which this version of @canopy-io/node does not understand. It knows ${[...KNOWN_MODEL_VERSIONS].join(", ")}. Upgrade @canopy-io/node; until then this authorizer cannot decide, rather than guess.`
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
return page;
|
|
1167
|
+
}
|
|
1158
1168
|
var GRANTS_PATH = (identityId) => `/api/v1/identities/${encodeURIComponent(identityId)}/grants`;
|
|
1159
1169
|
var PARENTS_PATH = "/api/v1/nodes/parents";
|
|
1160
1170
|
var LocalAuthorizer = class {
|
|
@@ -1330,7 +1340,7 @@ var LocalAuthorizer = class {
|
|
|
1330
1340
|
return this.client.request("GET", path, {
|
|
1331
1341
|
...this.readOptions,
|
|
1332
1342
|
query
|
|
1333
|
-
});
|
|
1343
|
+
}).then((page) => understood(page, path));
|
|
1334
1344
|
},
|
|
1335
1345
|
{ page: 1, take: PAGE_SIZE },
|
|
1336
1346
|
{ maxPages: MAX_PAGES }
|
|
@@ -1410,12 +1420,15 @@ var LocalAuthorizer = class {
|
|
|
1410
1420
|
}
|
|
1411
1421
|
parentsFirstPage(etag) {
|
|
1412
1422
|
this.stats.treePages += 1;
|
|
1413
|
-
return this.client.requestConditional(
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1423
|
+
return this.client.requestConditional("GET", PARENTS_PATH, etag, {
|
|
1424
|
+
...this.readOptions,
|
|
1425
|
+
query: { page: 1, take: PAGE_SIZE }
|
|
1426
|
+
}).then((result) => {
|
|
1427
|
+
if (result.modified) {
|
|
1428
|
+
understood(result.data, PARENTS_PATH);
|
|
1429
|
+
}
|
|
1430
|
+
return result;
|
|
1431
|
+
});
|
|
1419
1432
|
}
|
|
1420
1433
|
/** The first page's edges followed by every later page's. */
|
|
1421
1434
|
async parentsRemainingPages(first) {
|
|
@@ -1429,7 +1442,7 @@ var LocalAuthorizer = class {
|
|
|
1429
1442
|
return this.client.request("GET", PARENTS_PATH, {
|
|
1430
1443
|
...this.readOptions,
|
|
1431
1444
|
query
|
|
1432
|
-
});
|
|
1445
|
+
}).then((page) => understood(page, PARENTS_PATH));
|
|
1433
1446
|
},
|
|
1434
1447
|
{ page: first.pagination.page + 1, take: PAGE_SIZE },
|
|
1435
1448
|
{ maxPages: MAX_PAGES - 1 }
|