UNPKG

@cerbos/embedded

Version:

Client library for interacting with embedded Cerbos policy decision points generated by Cerbos Hub from server-side Node.js and browser-based applications

117 lines 4.27 kB
import { monotonicFactory } from "ulid"; import { checkInputFromProtobuf, checkOutputFromProtobuf, requireField, } from "@cerbos/core/~internal"; export class DecisionLogger { log; userAgent; ulid; constructor(log, userAgent) { this.log = log; this.userAgent = userAgent; this.ulid = monotonicFactory(); } async logCheckResources(request, auxData, headers, response, bundleMetadata, error) { const callId = this.ulid(); const inputs = request.resources.map(({ resource, actions }) => ({ ...checkInputFromProtobuf({ $typeName: "cerbos.engine.v1.CheckInput", requestId: request.requestId, principal: request.principal, resource, actions, }), auxData, })); const outputs = []; const effectivePolicies = {}; if (response) { response.cerbosCallId = callId; for (const result of response.results) { requireField("CheckResourcesResponse.ResultEntry.resource", result.resource); requireField("CheckResourcesResponse.ResultEntry.meta", result.meta); const actions = {}; for (const [action, effect] of Object.entries(result.actions)) { const meta = result.meta.actions[action]; actions[action] = { $typeName: "cerbos.engine.v1.CheckOutput.ActionEffect", effect, policy: meta?.matchedPolicy ?? "", scope: meta?.matchedScope ?? "", }; if (meta?.matchedPolicy && !effectivePolicies[meta.matchedPolicy]) { for (const ancestor of ancestors(meta.matchedPolicy)) { effectivePolicies[ancestor] ??= { commit_hash: bundleMetadata.commit, ...bundleMetadata.sourceAttributes[`cerbos.${ancestor}`], }; } } } outputs.push(checkOutputFromProtobuf({ $typeName: "cerbos.engine.v1.CheckOutput", requestId: response.requestId, resourceId: result.resource.id, actions, outputs: result.outputs, effectiveDerivedRoles: result.meta.effectiveDerivedRoles, validationErrors: result.validationErrors, })); } } await this.log({ callId, method: { name: "CheckResources", inputs, outputs, error: errorMessage(error), }, timestamp: new Date(), metadata: metadata(headers), oversized: false, auditTrail: { effectivePolicies, }, peer: { address: "", authInfo: "", forwardedFor: "", userAgent: this.userAgent, }, policySource: { kind: "embeddedPDP", url: bundleMetadata.url ?? "", commit: bundleMetadata.commit, builtAt: bundleMetadata.builtAt, }, }); } } function errorMessage(error) { if (error === undefined) { return undefined; } if (error instanceof Error) { return error.message; } return "Unknown error"; } function metadata(headers) { const metadata = {}; for (const [name, value] of headers) { if (name !== "user-agent") { (metadata[name] ??= []).push(value); } } return metadata; } const scopedPolicyIdPattern = /\.v[^/]+(?<separator>\/)[^/]+$/d; function* ancestors(policyId) { const match = scopedPolicyIdPattern.exec(policyId); if (match) { for (let end = match.indices.groups.separator[0]; end > 0; end = policyId.indexOf(".", end + 1)) { yield policyId.substring(0, end); } } yield policyId; } //# sourceMappingURL=logger.js.map