@atlasauth/pca-rag 0.0.0-stage → 0.1.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/index.d.ts +226 -0
- package/dist/index.js +307 -0
- package/dist/index.js.map +1 -0
- package/package.json +31 -3
- package/README.md +0 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @atlasauth/pca-rag — FGA-for-RAG.
|
|
3
|
+
*
|
|
4
|
+
* Retrieval-time, per-principal document filtering driven by the PCA policy engine. Given a
|
|
5
|
+
* principal (or a verified PCActn's holder), a candidate set of documents that each carry ACL
|
|
6
|
+
* metadata (a `{ relation, object }` ACL entry, or `relation:object` tags), and a policy (raw PCA
|
|
7
|
+
* predicates, or an imported OpenFGA/Zanzibar ReBAC model+tuples), this returns ONLY the documents
|
|
8
|
+
* the principal may see — deciding every candidate through the core evaluator / `member_of` relation
|
|
9
|
+
* closure in `@atlasauth/pca`, and reusing `@atlasauth/pca-policy-bridge` to compile ReBAC relation
|
|
10
|
+
* checks into PCA predicates.
|
|
11
|
+
*
|
|
12
|
+
* Two properties make this suitable for the PCA proof trace:
|
|
13
|
+
* 1. FAIL CLOSED. A document is admitted ONLY when a permit predicate cleanly matches (verb =
|
|
14
|
+
* relation, resource = object, every `where` condition `true`) and no deny predicate matches.
|
|
15
|
+
* Anything unknown — no ACL, an unresolved relation, a malformed document, an incomplete policy
|
|
16
|
+
* translation — drops the document. The model can never see an unauthorized chunk.
|
|
17
|
+
* 2. AUDITABLE. Every decision is captured in a {@link FilterDecision}: which documents passed,
|
|
18
|
+
* which were dropped and why, the exact permit predicate that authorized each one, and a
|
|
19
|
+
* content-addressed `digest` of the whole decision set that can be bound into a receipt / proof.
|
|
20
|
+
*
|
|
21
|
+
* Decisions use the SAME evaluator the adjudicator uses, so "what the retriever filtered" and "what
|
|
22
|
+
* the authority system would admit" cannot drift apart.
|
|
23
|
+
*/
|
|
24
|
+
import type { PCActn, Predicate } from '@atlasauth/pca';
|
|
25
|
+
import { type TranslationReport } from '@atlasauth/pca-policy-bridge';
|
|
26
|
+
/**
|
|
27
|
+
* The retrieval principal. `id` is matched against the policy's subject (`subject.id` in a PCA
|
|
28
|
+
* predicate, the `user` of an OpenFGA tuple). `attributes` are exposed to policy conditions as
|
|
29
|
+
* `subject.*`; `env` is exposed as `env.*` (e.g. a group-adjacency map a `member_of` condition's
|
|
30
|
+
* `collection` resolves against).
|
|
31
|
+
*/
|
|
32
|
+
export interface Principal {
|
|
33
|
+
id: string;
|
|
34
|
+
attributes?: Record<string, unknown>;
|
|
35
|
+
env?: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
/** A principal, or just its id (shorthand for `{ id }`). */
|
|
38
|
+
export type PrincipalInput = Principal | string;
|
|
39
|
+
/**
|
|
40
|
+
* Derive a {@link Principal} from a (already verified) PCActn: the acting identity is the LEAF
|
|
41
|
+
* capability holder — the key the action was ultimately delegated to. Pass `opts.id` to map that
|
|
42
|
+
* holder key to the identity your policy is keyed on (e.g. an OpenFGA `user:alice`); it defaults to
|
|
43
|
+
* the raw leaf-holder key. Throws on a PCActn with no capability chain (a malformed / unverified
|
|
44
|
+
* object), rather than silently producing an empty principal.
|
|
45
|
+
*/
|
|
46
|
+
export declare function principalFromPCActn(p: Pick<PCActn, 'cap_chain'>, opts?: {
|
|
47
|
+
id?: string;
|
|
48
|
+
attributes?: Record<string, unknown>;
|
|
49
|
+
env?: Record<string, unknown>;
|
|
50
|
+
}): Principal;
|
|
51
|
+
/** One ACL entry: the principal must hold `relation` on `object` (an OpenFGA relation check). */
|
|
52
|
+
export interface DocAcl {
|
|
53
|
+
relation: string;
|
|
54
|
+
object: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The minimal document shape the default extractor understands: a stable `id`, plus ACL metadata as
|
|
58
|
+
* an `acl` entry (single or list) and/or `relation:object` tag strings. A document needs AT LEAST ONE
|
|
59
|
+
* decidable ACL entry (via `acl` or `tags`) to be admissible — one with none fails closed.
|
|
60
|
+
*/
|
|
61
|
+
export interface AclDocument {
|
|
62
|
+
id: string;
|
|
63
|
+
acl?: DocAcl | DocAcl[];
|
|
64
|
+
tags?: string[];
|
|
65
|
+
[k: string]: unknown;
|
|
66
|
+
}
|
|
67
|
+
/** Collect ACL entries from freeform `acl` + `tags` metadata (both `unknown`; proto-safe narrowing). */
|
|
68
|
+
export declare function aclsFromMetadata(acl: unknown, tags: unknown): DocAcl[];
|
|
69
|
+
/**
|
|
70
|
+
* A policy for the filter. One of:
|
|
71
|
+
* - a bare `Predicate[]` (raw PCA permits);
|
|
72
|
+
* - `{ openfga: { model, tuples } }` — an OpenFGA/Zanzibar authorization model + relationship
|
|
73
|
+
* tuples, compiled via {@link openfgaToPca} (relation closures — computedUserset, union,
|
|
74
|
+
* intersection, difference, tupleToUserset — are resolved into concrete permits);
|
|
75
|
+
* - `{ predicates, denies?, report? }` — an envelope-shaped result (e.g. a bridge `BridgeResult`),
|
|
76
|
+
* where `denies` is applied with deny-overrides-permit semantics.
|
|
77
|
+
*/
|
|
78
|
+
export type PolicyInput = Predicate[] | {
|
|
79
|
+
openfga: {
|
|
80
|
+
model: unknown;
|
|
81
|
+
tuples: unknown;
|
|
82
|
+
};
|
|
83
|
+
} | {
|
|
84
|
+
predicates: Predicate[];
|
|
85
|
+
denies?: Predicate[];
|
|
86
|
+
report?: TranslationReport;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* A compiled policy: a permit list, a deny list and whether the source translation was INCOMPLETE
|
|
90
|
+
* (a non-empty `report.errors` — in which case the whole policy fails closed and nothing is admitted).
|
|
91
|
+
* Compile once with {@link compilePolicy} and reuse across retrievals to avoid recompiling per call.
|
|
92
|
+
*/
|
|
93
|
+
export interface CompiledPolicy {
|
|
94
|
+
readonly predicates: Predicate[];
|
|
95
|
+
readonly denies: Predicate[];
|
|
96
|
+
readonly incomplete: boolean;
|
|
97
|
+
readonly report?: TranslationReport;
|
|
98
|
+
}
|
|
99
|
+
/** Compile any {@link PolicyInput} (or pass through an already-{@link CompiledPolicy}). */
|
|
100
|
+
export declare function compilePolicy(policy: PolicyInput | CompiledPolicy): CompiledPolicy;
|
|
101
|
+
/** Per-document decision — the auditable record of why one candidate passed or was dropped. */
|
|
102
|
+
export interface DocDecision {
|
|
103
|
+
id: string;
|
|
104
|
+
allowed: boolean;
|
|
105
|
+
/** The ACL entry that granted access (present only when `allowed`). */
|
|
106
|
+
via?: DocAcl;
|
|
107
|
+
/** The exact permit predicate that matched (proof: which grant authorized this document). */
|
|
108
|
+
matched?: Predicate;
|
|
109
|
+
/** Human-readable reason — the fail-closed cause for a drop, or the grant for an allow. */
|
|
110
|
+
reason: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The full decision for a filter run — suitable to attach to a PCA proof / receipt. `digest` is a
|
|
114
|
+
* content-addressed commitment to the decision (principal + the admitted/dropped id sets), so a
|
|
115
|
+
* verifier can confirm the model was handed exactly these documents and no others.
|
|
116
|
+
*/
|
|
117
|
+
export interface FilterDecision {
|
|
118
|
+
principal: string;
|
|
119
|
+
considered: number;
|
|
120
|
+
/** IDs admitted (the model may see these), in candidate order. */
|
|
121
|
+
allowedIds: string[];
|
|
122
|
+
/** IDs dropped (not authorized / unknown — fail closed), in candidate order. */
|
|
123
|
+
droppedIds: string[];
|
|
124
|
+
/** One record per candidate. */
|
|
125
|
+
decisions: DocDecision[];
|
|
126
|
+
/** True when the policy translation was incomplete → every candidate fails closed. */
|
|
127
|
+
policyIncomplete: boolean;
|
|
128
|
+
/** The policy-translation report, when the policy was imported (OpenFGA). */
|
|
129
|
+
report?: TranslationReport;
|
|
130
|
+
/** b64u content-address of this decision set (binds into the proof trace). */
|
|
131
|
+
digest: string;
|
|
132
|
+
}
|
|
133
|
+
/** Result of {@link filterDocuments}: the admitted documents plus the {@link FilterDecision}. */
|
|
134
|
+
export interface FilterResult<D> {
|
|
135
|
+
documents: D[];
|
|
136
|
+
decision: FilterDecision;
|
|
137
|
+
}
|
|
138
|
+
/** Options controlling how ACL metadata is read from a document. */
|
|
139
|
+
export interface FilterOptions<D extends AclDocument> {
|
|
140
|
+
/** Stable id for a document (default: `doc.id`, else a positional `doc#<index>`). */
|
|
141
|
+
getId?: (doc: D, index: number) => string;
|
|
142
|
+
/** ACL entries for a document (default: `doc.acl` + `relation:object` `doc.tags`). */
|
|
143
|
+
getAcls?: (doc: D) => DocAcl[];
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Filter a candidate set to the documents `principal` may see under `policy`. Returns the admitted
|
|
147
|
+
* documents (in candidate order) and a {@link FilterDecision} proof trace. FAILS CLOSED: a document
|
|
148
|
+
* is admitted only when a permit predicate cleanly matches one of its ACL entries and no deny matches;
|
|
149
|
+
* anything unknown is dropped.
|
|
150
|
+
*/
|
|
151
|
+
export declare function filterDocuments<D extends AclDocument>(principal: PrincipalInput, candidates: D[], policy: PolicyInput | CompiledPolicy, opts?: FilterOptions<D>): FilterResult<D>;
|
|
152
|
+
/** A generic retriever: returns candidate documents for a query. */
|
|
153
|
+
export interface RagRetriever<D extends AclDocument = AclDocument> {
|
|
154
|
+
retrieve(query: string, k?: number): Promise<D[]> | D[];
|
|
155
|
+
}
|
|
156
|
+
/** A retriever whose results are PCA-filtered before they reach the model. */
|
|
157
|
+
export interface FilteredRetriever<D extends AclDocument = AclDocument> {
|
|
158
|
+
retrieve(query: string, k?: number): Promise<D[]>;
|
|
159
|
+
/** The decision from the most recent `retrieve` (the proof trace), or `undefined` if none yet. */
|
|
160
|
+
lastDecision(): FilterDecision | undefined;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Wrap a generic {@link RagRetriever} so every result set is filtered to what `principal` may see
|
|
164
|
+
* BEFORE it reaches the model. The wrapper exposes the same `retrieve` plus `lastDecision()` for audit.
|
|
165
|
+
*/
|
|
166
|
+
export declare function withPcaFilter<D extends AclDocument>(retriever: RagRetriever<D>, principal: PrincipalInput, policy: PolicyInput | CompiledPolicy, opts?: FilterOptions<D>): FilteredRetriever<D>;
|
|
167
|
+
/** Minimal structural shape of a LangChain `Document` (we never import `@langchain/*`). */
|
|
168
|
+
export interface LangChainDocumentLike {
|
|
169
|
+
pageContent: string;
|
|
170
|
+
metadata?: Record<string, unknown>;
|
|
171
|
+
}
|
|
172
|
+
/** Minimal structural shape of a LangChain retriever (`invoke` or the older `getRelevantDocuments`). */
|
|
173
|
+
export interface LangChainRetrieverLike<D extends LangChainDocumentLike = LangChainDocumentLike> {
|
|
174
|
+
invoke?(input: string): Promise<D[]> | D[];
|
|
175
|
+
getRelevantDocuments?(query: string): Promise<D[]> | D[];
|
|
176
|
+
}
|
|
177
|
+
/** How to read ACL metadata off a LangChain document (defaults read `metadata.acl` + `metadata.tags`). */
|
|
178
|
+
export interface LangChainAdapterOptions<D extends LangChainDocumentLike = LangChainDocumentLike> {
|
|
179
|
+
getId?: (doc: D, index: number) => string;
|
|
180
|
+
getAcls?: (doc: D) => DocAcl[];
|
|
181
|
+
}
|
|
182
|
+
/** A LangChain-shaped retriever whose results are PCA-filtered post-retrieval. */
|
|
183
|
+
export interface FilteredLangChainRetriever<D extends LangChainDocumentLike = LangChainDocumentLike> {
|
|
184
|
+
invoke(input: string): Promise<D[]>;
|
|
185
|
+
getRelevantDocuments(query: string): Promise<D[]>;
|
|
186
|
+
lastDecision(): FilterDecision | undefined;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Wrap a LangChain-shaped retriever. Results are filtered post-retrieval (before they reach the
|
|
190
|
+
* model); ACLs are read from each document's `metadata` by default. The underlying retriever is
|
|
191
|
+
* called via `invoke` when present, else `getRelevantDocuments`.
|
|
192
|
+
*/
|
|
193
|
+
export declare function withLangChainPcaFilter<D extends LangChainDocumentLike>(retriever: LangChainRetrieverLike<D>, principal: PrincipalInput, policy: PolicyInput | CompiledPolicy, opts?: LangChainAdapterOptions<D>): FilteredLangChainRetriever<D>;
|
|
194
|
+
/** Minimal structural shape of a LlamaIndex node. */
|
|
195
|
+
export interface LlamaIndexNodeLike {
|
|
196
|
+
id_?: string;
|
|
197
|
+
metadata?: Record<string, unknown>;
|
|
198
|
+
}
|
|
199
|
+
/** Minimal structural shape of a LlamaIndex `NodeWithScore`. */
|
|
200
|
+
export interface LlamaIndexNodeWithScoreLike<N extends LlamaIndexNodeLike = LlamaIndexNodeLike> {
|
|
201
|
+
node: N;
|
|
202
|
+
score?: number;
|
|
203
|
+
}
|
|
204
|
+
/** Minimal structural shape of a LlamaIndex retriever. */
|
|
205
|
+
export interface LlamaIndexRetrieverLike<N extends LlamaIndexNodeLike = LlamaIndexNodeLike> {
|
|
206
|
+
retrieve(params: {
|
|
207
|
+
query: string;
|
|
208
|
+
} | string): Promise<Array<LlamaIndexNodeWithScoreLike<N>>> | Array<LlamaIndexNodeWithScoreLike<N>>;
|
|
209
|
+
}
|
|
210
|
+
/** How to read ACL metadata off a LlamaIndex node (defaults read `node.metadata.acl` + `.tags`). */
|
|
211
|
+
export interface LlamaIndexAdapterOptions<N extends LlamaIndexNodeLike = LlamaIndexNodeLike> {
|
|
212
|
+
getId?: (item: LlamaIndexNodeWithScoreLike<N>, index: number) => string;
|
|
213
|
+
getAcls?: (item: LlamaIndexNodeWithScoreLike<N>) => DocAcl[];
|
|
214
|
+
}
|
|
215
|
+
/** A LlamaIndex-shaped retriever whose results are PCA-filtered post-retrieval. */
|
|
216
|
+
export interface FilteredLlamaIndexRetriever<N extends LlamaIndexNodeLike = LlamaIndexNodeLike> {
|
|
217
|
+
retrieve(params: {
|
|
218
|
+
query: string;
|
|
219
|
+
} | string): Promise<Array<LlamaIndexNodeWithScoreLike<N>>>;
|
|
220
|
+
lastDecision(): FilterDecision | undefined;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Wrap a LlamaIndex-shaped retriever. The returned `NodeWithScore[]` is filtered post-retrieval
|
|
224
|
+
* (before it reaches the model); ACLs are read from each node's `metadata` by default.
|
|
225
|
+
*/
|
|
226
|
+
export declare function withLlamaIndexPcaFilter<N extends LlamaIndexNodeLike>(retriever: LlamaIndexRetrieverLike<N>, principal: PrincipalInput, policy: PolicyInput | CompiledPolicy, opts?: LlamaIndexAdapterOptions<N>): FilteredLlamaIndexRetriever<N>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @atlasauth/pca-rag — FGA-for-RAG.
|
|
4
|
+
*
|
|
5
|
+
* Retrieval-time, per-principal document filtering driven by the PCA policy engine. Given a
|
|
6
|
+
* principal (or a verified PCActn's holder), a candidate set of documents that each carry ACL
|
|
7
|
+
* metadata (a `{ relation, object }` ACL entry, or `relation:object` tags), and a policy (raw PCA
|
|
8
|
+
* predicates, or an imported OpenFGA/Zanzibar ReBAC model+tuples), this returns ONLY the documents
|
|
9
|
+
* the principal may see — deciding every candidate through the core evaluator / `member_of` relation
|
|
10
|
+
* closure in `@atlasauth/pca`, and reusing `@atlasauth/pca-policy-bridge` to compile ReBAC relation
|
|
11
|
+
* checks into PCA predicates.
|
|
12
|
+
*
|
|
13
|
+
* Two properties make this suitable for the PCA proof trace:
|
|
14
|
+
* 1. FAIL CLOSED. A document is admitted ONLY when a permit predicate cleanly matches (verb =
|
|
15
|
+
* relation, resource = object, every `where` condition `true`) and no deny predicate matches.
|
|
16
|
+
* Anything unknown — no ACL, an unresolved relation, a malformed document, an incomplete policy
|
|
17
|
+
* translation — drops the document. The model can never see an unauthorized chunk.
|
|
18
|
+
* 2. AUDITABLE. Every decision is captured in a {@link FilterDecision}: which documents passed,
|
|
19
|
+
* which were dropped and why, the exact permit predicate that authorized each one, and a
|
|
20
|
+
* content-addressed `digest` of the whole decision set that can be bound into a receipt / proof.
|
|
21
|
+
*
|
|
22
|
+
* Decisions use the SAME evaluator the adjudicator uses, so "what the retriever filtered" and "what
|
|
23
|
+
* the authority system would admit" cannot drift apart.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.principalFromPCActn = principalFromPCActn;
|
|
27
|
+
exports.aclsFromMetadata = aclsFromMetadata;
|
|
28
|
+
exports.compilePolicy = compilePolicy;
|
|
29
|
+
exports.filterDocuments = filterDocuments;
|
|
30
|
+
exports.withPcaFilter = withPcaFilter;
|
|
31
|
+
exports.withLangChainPcaFilter = withLangChainPcaFilter;
|
|
32
|
+
exports.withLlamaIndexPcaFilter = withLlamaIndexPcaFilter;
|
|
33
|
+
const pca_1 = require("@atlasauth/pca");
|
|
34
|
+
const pca_policy_bridge_1 = require("@atlasauth/pca-policy-bridge");
|
|
35
|
+
function toPrincipal(p) {
|
|
36
|
+
return typeof p === 'string' ? { id: p } : p;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Derive a {@link Principal} from a (already verified) PCActn: the acting identity is the LEAF
|
|
40
|
+
* capability holder — the key the action was ultimately delegated to. Pass `opts.id` to map that
|
|
41
|
+
* holder key to the identity your policy is keyed on (e.g. an OpenFGA `user:alice`); it defaults to
|
|
42
|
+
* the raw leaf-holder key. Throws on a PCActn with no capability chain (a malformed / unverified
|
|
43
|
+
* object), rather than silently producing an empty principal.
|
|
44
|
+
*/
|
|
45
|
+
function principalFromPCActn(p, opts) {
|
|
46
|
+
const chain = Array.isArray(p?.cap_chain) ? p.cap_chain : [];
|
|
47
|
+
const leaf = chain.at(-1);
|
|
48
|
+
if (!leaf || typeof leaf.holder !== 'string' || leaf.holder.length === 0) {
|
|
49
|
+
throw new TypeError('principalFromPCActn: PCActn has no leaf capability holder');
|
|
50
|
+
}
|
|
51
|
+
const principal = { id: opts?.id ?? leaf.holder };
|
|
52
|
+
if (opts?.attributes !== undefined)
|
|
53
|
+
principal.attributes = opts.attributes;
|
|
54
|
+
if (opts?.env !== undefined)
|
|
55
|
+
principal.env = opts.env;
|
|
56
|
+
return principal;
|
|
57
|
+
}
|
|
58
|
+
function isDocAcl(v) {
|
|
59
|
+
if (v === null || typeof v !== 'object')
|
|
60
|
+
return false;
|
|
61
|
+
const rel = v.relation;
|
|
62
|
+
const obj = v.object;
|
|
63
|
+
return typeof rel === 'string' && rel.length > 0 && typeof obj === 'string' && obj.length > 0;
|
|
64
|
+
}
|
|
65
|
+
function aclArray(acl) {
|
|
66
|
+
if (Array.isArray(acl))
|
|
67
|
+
return acl.filter(isDocAcl);
|
|
68
|
+
return isDocAcl(acl) ? [acl] : [];
|
|
69
|
+
}
|
|
70
|
+
/** A `relation:object` tag → an ACL entry. The split is at the FIRST ':' so an object id may itself
|
|
71
|
+
* contain ':' (e.g. `viewer:document:readme` → relation `viewer`, object `document:readme`). */
|
|
72
|
+
function tagToAcl(tag) {
|
|
73
|
+
if (typeof tag !== 'string')
|
|
74
|
+
return null;
|
|
75
|
+
const i = tag.indexOf(':');
|
|
76
|
+
if (i <= 0 || i >= tag.length - 1)
|
|
77
|
+
return null;
|
|
78
|
+
return { relation: tag.slice(0, i), object: tag.slice(i + 1) };
|
|
79
|
+
}
|
|
80
|
+
/** Collect ACL entries from freeform `acl` + `tags` metadata (both `unknown`; proto-safe narrowing). */
|
|
81
|
+
function aclsFromMetadata(acl, tags) {
|
|
82
|
+
const out = aclArray(acl);
|
|
83
|
+
if (Array.isArray(tags)) {
|
|
84
|
+
for (const t of tags) {
|
|
85
|
+
const a = tagToAcl(t);
|
|
86
|
+
if (a !== null)
|
|
87
|
+
out.push(a);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
function isCompiledPolicy(p) {
|
|
93
|
+
return (p !== null &&
|
|
94
|
+
typeof p === 'object' &&
|
|
95
|
+
!Array.isArray(p) &&
|
|
96
|
+
'incomplete' in p &&
|
|
97
|
+
typeof p.incomplete === 'boolean');
|
|
98
|
+
}
|
|
99
|
+
/** Compile any {@link PolicyInput} (or pass through an already-{@link CompiledPolicy}). */
|
|
100
|
+
function compilePolicy(policy) {
|
|
101
|
+
if (isCompiledPolicy(policy))
|
|
102
|
+
return policy;
|
|
103
|
+
if (Array.isArray(policy))
|
|
104
|
+
return { predicates: policy, denies: [], incomplete: false };
|
|
105
|
+
if ('openfga' in policy) {
|
|
106
|
+
const br = (0, pca_policy_bridge_1.openfgaToPca)(policy.openfga.model, policy.openfga.tuples);
|
|
107
|
+
return {
|
|
108
|
+
predicates: br.predicates,
|
|
109
|
+
denies: br.denies,
|
|
110
|
+
report: br.report,
|
|
111
|
+
incomplete: br.report.errors.length > 0,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const predicates = Array.isArray(policy.predicates) ? policy.predicates : [];
|
|
115
|
+
const denies = Array.isArray(policy.denies) ? policy.denies : [];
|
|
116
|
+
const report = policy.report;
|
|
117
|
+
return { predicates, denies, report, incomplete: report !== undefined && report.errors.length > 0 };
|
|
118
|
+
}
|
|
119
|
+
/** Build the evaluation context for checking ONE ACL entry for a principal. */
|
|
120
|
+
function buildContext(principal, acl) {
|
|
121
|
+
const subject = { ...(principal.attributes ?? {}), id: principal.id };
|
|
122
|
+
const ctx = {
|
|
123
|
+
action: { verb: acl.relation, resource: acl.object },
|
|
124
|
+
subject,
|
|
125
|
+
};
|
|
126
|
+
if (principal.env !== undefined)
|
|
127
|
+
ctx.env = principal.env;
|
|
128
|
+
return ctx;
|
|
129
|
+
}
|
|
130
|
+
/** Decide a single document. Returns the per-document record; `allowed` governs admission. */
|
|
131
|
+
function decideDocument(id, acls, principal, compiled) {
|
|
132
|
+
if (compiled.incomplete) {
|
|
133
|
+
return { id, allowed: false, reason: 'policy translation incomplete (fail closed)' };
|
|
134
|
+
}
|
|
135
|
+
if (acls.length === 0) {
|
|
136
|
+
return { id, allowed: false, reason: 'no decidable ACL metadata (fail closed)' };
|
|
137
|
+
}
|
|
138
|
+
let lastReason = 'no relation grants access (fail closed)';
|
|
139
|
+
for (const acl of acls) {
|
|
140
|
+
let res;
|
|
141
|
+
try {
|
|
142
|
+
res = (0, pca_policy_bridge_1.decide)({ predicates: compiled.predicates, denies: compiled.denies }, buildContext(principal, acl));
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
lastReason = 'evaluator error (fail closed)';
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (res.allowed) {
|
|
149
|
+
const d = {
|
|
150
|
+
id,
|
|
151
|
+
allowed: true,
|
|
152
|
+
via: acl,
|
|
153
|
+
reason: `granted: ${principal.id} has ${acl.relation} on ${acl.object}`,
|
|
154
|
+
};
|
|
155
|
+
if (res.matched !== undefined)
|
|
156
|
+
d.matched = res.matched;
|
|
157
|
+
return d;
|
|
158
|
+
}
|
|
159
|
+
if (res.reason !== undefined)
|
|
160
|
+
lastReason = res.reason;
|
|
161
|
+
}
|
|
162
|
+
return { id, allowed: false, reason: lastReason };
|
|
163
|
+
}
|
|
164
|
+
function runFilter(principalInput, candidates, policyInput, ex) {
|
|
165
|
+
const principal = toPrincipal(principalInput);
|
|
166
|
+
const compiled = compilePolicy(policyInput);
|
|
167
|
+
const list = Array.isArray(candidates) ? candidates : [];
|
|
168
|
+
const documents = [];
|
|
169
|
+
const decisions = [];
|
|
170
|
+
const allowedIds = [];
|
|
171
|
+
const droppedIds = [];
|
|
172
|
+
for (let i = 0; i < list.length; i++) {
|
|
173
|
+
const doc = list[i];
|
|
174
|
+
let id;
|
|
175
|
+
let acls;
|
|
176
|
+
try {
|
|
177
|
+
id = ex.id(doc, i);
|
|
178
|
+
acls = ex.acls(doc);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// A document whose metadata cannot even be read is unknown → fail closed.
|
|
182
|
+
const fid = `doc#${i}`;
|
|
183
|
+
decisions.push({ id: fid, allowed: false, reason: 'unreadable document metadata (fail closed)' });
|
|
184
|
+
droppedIds.push(fid);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (typeof id !== 'string' || id.length === 0)
|
|
188
|
+
id = `doc#${i}`;
|
|
189
|
+
const decision = decideDocument(id, acls, principal, compiled);
|
|
190
|
+
decisions.push(decision);
|
|
191
|
+
if (decision.allowed) {
|
|
192
|
+
documents.push(doc);
|
|
193
|
+
allowedIds.push(id);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
droppedIds.push(id);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const base = {
|
|
200
|
+
principal: principal.id,
|
|
201
|
+
considered: list.length,
|
|
202
|
+
allowedIds,
|
|
203
|
+
droppedIds,
|
|
204
|
+
policyIncomplete: compiled.incomplete,
|
|
205
|
+
};
|
|
206
|
+
const digest = (0, pca_1.hashCanonical)({ v: 1, kind: 'pca-rag/filter', ...base });
|
|
207
|
+
const decision = { ...base, decisions, digest };
|
|
208
|
+
if (compiled.report !== undefined)
|
|
209
|
+
decision.report = compiled.report;
|
|
210
|
+
return { documents, decision };
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Filter a candidate set to the documents `principal` may see under `policy`. Returns the admitted
|
|
214
|
+
* documents (in candidate order) and a {@link FilterDecision} proof trace. FAILS CLOSED: a document
|
|
215
|
+
* is admitted only when a permit predicate cleanly matches one of its ACL entries and no deny matches;
|
|
216
|
+
* anything unknown is dropped.
|
|
217
|
+
*/
|
|
218
|
+
function filterDocuments(principal, candidates, policy, opts) {
|
|
219
|
+
const ex = {
|
|
220
|
+
id: opts?.getId ?? ((doc) => doc.id),
|
|
221
|
+
acls: opts?.getAcls ?? ((doc) => aclsFromMetadata(doc.acl, doc.tags)),
|
|
222
|
+
};
|
|
223
|
+
return runFilter(principal, candidates, policy, ex);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Wrap a generic {@link RagRetriever} so every result set is filtered to what `principal` may see
|
|
227
|
+
* BEFORE it reaches the model. The wrapper exposes the same `retrieve` plus `lastDecision()` for audit.
|
|
228
|
+
*/
|
|
229
|
+
function withPcaFilter(retriever, principal, policy, opts) {
|
|
230
|
+
const compiled = compilePolicy(policy);
|
|
231
|
+
let last;
|
|
232
|
+
return {
|
|
233
|
+
async retrieve(query, k) {
|
|
234
|
+
const docs = await retriever.retrieve(query, k);
|
|
235
|
+
const res = filterDocuments(principal, Array.isArray(docs) ? docs : [], compiled, opts);
|
|
236
|
+
last = res.decision;
|
|
237
|
+
return res.documents;
|
|
238
|
+
},
|
|
239
|
+
lastDecision() {
|
|
240
|
+
return last;
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
// ---- framework-shaped adapters (structural, optional-peer; no heavy deps imported) ---------------
|
|
245
|
+
function metaString(meta, key) {
|
|
246
|
+
if (meta === undefined || meta === null)
|
|
247
|
+
return undefined;
|
|
248
|
+
const v = meta[key];
|
|
249
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Wrap a LangChain-shaped retriever. Results are filtered post-retrieval (before they reach the
|
|
253
|
+
* model); ACLs are read from each document's `metadata` by default. The underlying retriever is
|
|
254
|
+
* called via `invoke` when present, else `getRelevantDocuments`.
|
|
255
|
+
*/
|
|
256
|
+
function withLangChainPcaFilter(retriever, principal, policy, opts) {
|
|
257
|
+
const compiled = compilePolicy(policy);
|
|
258
|
+
let last;
|
|
259
|
+
const ex = {
|
|
260
|
+
id: opts?.getId ?? ((doc, i) => metaString(doc.metadata, 'id') ?? metaString(doc.metadata, 'source') ?? `doc#${i}`),
|
|
261
|
+
acls: opts?.getAcls ?? ((doc) => aclsFromMetadata(doc.metadata?.['acl'], doc.metadata?.['tags'])),
|
|
262
|
+
};
|
|
263
|
+
const fetch = async (input) => {
|
|
264
|
+
if (typeof retriever.invoke === 'function')
|
|
265
|
+
return await retriever.invoke(input);
|
|
266
|
+
if (typeof retriever.getRelevantDocuments === 'function')
|
|
267
|
+
return await retriever.getRelevantDocuments(input);
|
|
268
|
+
throw new TypeError('withLangChainPcaFilter: retriever has neither invoke nor getRelevantDocuments');
|
|
269
|
+
};
|
|
270
|
+
const run = async (input) => {
|
|
271
|
+
const docs = await fetch(input);
|
|
272
|
+
const res = runFilter(principal, Array.isArray(docs) ? docs : [], compiled, ex);
|
|
273
|
+
last = res.decision;
|
|
274
|
+
return res.documents;
|
|
275
|
+
};
|
|
276
|
+
return {
|
|
277
|
+
invoke: run,
|
|
278
|
+
getRelevantDocuments: run,
|
|
279
|
+
lastDecision: () => last,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Wrap a LlamaIndex-shaped retriever. The returned `NodeWithScore[]` is filtered post-retrieval
|
|
284
|
+
* (before it reaches the model); ACLs are read from each node's `metadata` by default.
|
|
285
|
+
*/
|
|
286
|
+
function withLlamaIndexPcaFilter(retriever, principal, policy, opts) {
|
|
287
|
+
const compiled = compilePolicy(policy);
|
|
288
|
+
let last;
|
|
289
|
+
const ex = {
|
|
290
|
+
id: opts?.getId ??
|
|
291
|
+
((item, i) => (typeof item.node?.id_ === 'string' && item.node.id_.length > 0 ? item.node.id_ : undefined) ??
|
|
292
|
+
metaString(item.node?.metadata, 'id') ??
|
|
293
|
+
`node#${i}`),
|
|
294
|
+
acls: opts?.getAcls ??
|
|
295
|
+
((item) => aclsFromMetadata(item.node?.metadata?.['acl'], item.node?.metadata?.['tags'])),
|
|
296
|
+
};
|
|
297
|
+
return {
|
|
298
|
+
async retrieve(params) {
|
|
299
|
+
const items = await retriever.retrieve(params);
|
|
300
|
+
const res = runFilter(principal, Array.isArray(items) ? items : [], compiled, ex);
|
|
301
|
+
last = res.decision;
|
|
302
|
+
return res.documents;
|
|
303
|
+
},
|
|
304
|
+
lastDecision: () => last,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;AAkCH,kDAaC;AA4CD,4CASC;AAyCD,sCAgBC;AAwKD,0CAWC;AAoBD,sCAmBC;AAwCD,wDA8BC;AAmCD,0DA6BC;AA1fD,wCAA+C;AAC/C,oEAA4F;AAmB5F,SAAS,WAAW,CAAC,CAAiB;IACpC,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CACjC,CAA4B,EAC5B,IAA2F;IAE3F,MAAM,KAAK,GAAoB,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,SAAS,CAAC,2DAA2D,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,SAAS,GAAc,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;IAC7D,IAAI,IAAI,EAAE,UAAU,KAAK,SAAS;QAAE,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IAC3E,IAAI,IAAI,EAAE,GAAG,KAAK,SAAS;QAAE,SAAS,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;IACtD,OAAO,SAAS,CAAC;AACnB,CAAC;AAsBD,SAAS,QAAQ,CAAC,CAAU;IAC1B,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,GAAG,GAAI,CAA4B,CAAC,QAAQ,CAAC;IACnD,MAAM,GAAG,GAAI,CAA0B,CAAC,MAAM,CAAC;IAC/C,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;AAChG,CAAC;AAED,SAAS,QAAQ,CAAC,GAAY;IAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,CAAC;AAED;iGACiG;AACjG,SAAS,QAAQ,CAAC,GAAY;IAC5B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,wGAAwG;AACxG,SAAgB,gBAAgB,CAAC,GAAY,EAAE,IAAa;IAC1D,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,CAAC,KAAK,IAAI;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AA8BD,SAAS,gBAAgB,CAAC,CAA+B;IACvD,OAAO,CACL,CAAC,KAAK,IAAI;QACV,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACjB,YAAY,IAAI,CAAC;QACjB,OAAQ,CAA8B,CAAC,UAAU,KAAK,SAAS,CAChE,CAAC;AACJ,CAAC;AAED,2FAA2F;AAC3F,SAAgB,aAAa,CAAC,MAAoC;IAChE,IAAI,gBAAgB,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACxF,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;QACxB,MAAM,EAAE,GAAG,IAAA,gCAAY,EAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrE,OAAO;YACL,UAAU,EAAE,EAAE,CAAC,UAAU;YACzB,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,UAAU,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;SACxC,CAAC;IACJ,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;AACtG,CAAC;AAmDD,+EAA+E;AAC/E,SAAS,YAAY,CAAC,SAAoB,EAAE,GAAW;IACrD,MAAM,OAAO,GAA4B,EAAE,GAAG,CAAC,SAAS,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC;IAC/F,MAAM,GAAG,GAAkB;QACzB,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QACpD,OAAO;KACR,CAAC;IACF,IAAI,SAAS,CAAC,GAAG,KAAK,SAAS;QAAE,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC;IACzD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8FAA8F;AAC9F,SAAS,cAAc,CACrB,EAAU,EACV,IAAc,EACd,SAAoB,EACpB,QAAwB;IAExB,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;QACxB,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;IACvF,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,yCAAyC,EAAE,CAAC;IACnF,CAAC;IACD,IAAI,UAAU,GAAG,yCAAyC,CAAC;IAC3D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAoB,CAAC;QACzB,IAAI,CAAC;YACH,GAAG,GAAG,IAAA,0BAAM,EAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,YAAY,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;QAC3G,CAAC;QAAC,MAAM,CAAC;YACP,UAAU,GAAG,+BAA+B,CAAC;YAC7C,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YAChB,MAAM,CAAC,GAAgB;gBACrB,EAAE;gBACF,OAAO,EAAE,IAAI;gBACb,GAAG,EAAE,GAAG;gBACR,MAAM,EAAE,YAAY,SAAS,CAAC,EAAE,QAAQ,GAAG,CAAC,QAAQ,OAAO,GAAG,CAAC,MAAM,EAAE;aACxE,CAAC;YACF,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS;gBAAE,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;YACvD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;YAAE,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC;IACxD,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,SAAS,CAChB,cAA8B,EAC9B,UAAe,EACf,WAAyC,EACzC,EAAiB;IAEjB,MAAM,SAAS,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAEzD,MAAM,SAAS,GAAQ,EAAE,CAAC;IAC1B,MAAM,SAAS,GAAkB,EAAE,CAAC;IACpC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,IAAI,EAAU,CAAC;QACf,IAAI,IAAc,CAAC;QACnB,IAAI,CAAC;YACH,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACnB,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,0EAA0E;YAC1E,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC;YACvB,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,4CAA4C,EAAE,CAAC,CAAC;YAClG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,SAAS;QACX,CAAC;QACD,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;YAAE,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;QAE/D,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC/D,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACrB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACpB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG;QACX,SAAS,EAAE,SAAS,CAAC,EAAE;QACvB,UAAU,EAAE,IAAI,CAAC,MAAM;QACvB,UAAU;QACV,UAAU;QACV,gBAAgB,EAAE,QAAQ,CAAC,UAAU;KACtC,CAAC;IACF,MAAM,MAAM,GAAG,IAAA,mBAAa,EAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAmB,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAChE,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS;QAAE,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAErE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AACjC,CAAC;AAUD;;;;;GAKG;AACH,SAAgB,eAAe,CAC7B,SAAyB,EACzB,UAAe,EACf,MAAoC,EACpC,IAAuB;IAEvB,MAAM,EAAE,GAAkB;QACxB,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,GAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,EAAE,IAAI,EAAE,OAAO,IAAI,CAAC,CAAC,GAAM,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;KACzE,CAAC;IACF,OAAO,SAAS,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAgBD;;;GAGG;AACH,SAAgB,aAAa,CAC3B,SAA0B,EAC1B,SAAyB,EACzB,MAAoC,EACpC,IAAuB;IAEvB,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,IAAgC,CAAC;IACrC,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,CAAU;YACtC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAChD,MAAM,GAAG,GAAG,eAAe,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YACxF,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;YACpB,OAAO,GAAG,CAAC,SAAS,CAAC;QACvB,CAAC;QACD,YAAY;YACV,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC;AAED,qGAAqG;AAErG,SAAS,UAAU,CAAC,IAAyC,EAAE,GAAW;IACxE,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC1D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/D,CAAC;AA2BD;;;;GAIG;AACH,SAAgB,sBAAsB,CACpC,SAAoC,EACpC,SAAyB,EACzB,MAAoC,EACpC,IAAiC;IAEjC,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,IAAgC,CAAC;IACrC,MAAM,EAAE,GAAkB;QACxB,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,GAAM,EAAE,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,OAAO,CAAC,EAAE,CAAC;QAC9H,IAAI,EAAE,IAAI,EAAE,OAAO,IAAI,CAAC,CAAC,GAAM,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;KACrG,CAAC;IAEF,MAAM,KAAK,GAAG,KAAK,EAAE,KAAa,EAAgB,EAAE;QAClD,IAAI,OAAO,SAAS,CAAC,MAAM,KAAK,UAAU;YAAE,OAAO,MAAM,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjF,IAAI,OAAO,SAAS,CAAC,oBAAoB,KAAK,UAAU;YAAE,OAAO,MAAM,SAAS,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC7G,MAAM,IAAI,SAAS,CAAC,+EAA+E,CAAC,CAAC;IACvG,CAAC,CAAC;IACF,MAAM,GAAG,GAAG,KAAK,EAAE,KAAa,EAAgB,EAAE;QAChD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,GAAG,GAAG,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QAChF,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;QACpB,OAAO,GAAG,CAAC,SAAS,CAAC;IACvB,CAAC,CAAC;IAEF,OAAO;QACL,MAAM,EAAE,GAAG;QACX,oBAAoB,EAAE,GAAG;QACzB,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI;KACzB,CAAC;AACJ,CAAC;AA+BD;;;GAGG;AACH,SAAgB,uBAAuB,CACrC,SAAqC,EACrC,SAAyB,EACzB,MAAoC,EACpC,IAAkC;IAElC,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,IAAgC,CAAC;IACrC,MAAM,EAAE,GAA+C;QACrD,EAAE,EACA,IAAI,EAAE,KAAK;YACX,CAAC,CAAC,IAAoC,EAAE,CAAS,EAAE,EAAE,CACnD,CAAC,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC5F,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC;gBACrC,QAAQ,CAAC,EAAE,CAAC;QAChB,IAAI,EACF,IAAI,EAAE,OAAO;YACb,CAAC,CAAC,IAAoC,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;KAC5H,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,MAAkC;YAC/C,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM,GAAG,GAAG,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YAClF,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;YACpB,OAAO,GAAG,CAAC,SAAS,CAAC;QACvB,CAAC;QACD,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI;KACzB,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlasauth/pca-rag",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "FGA-for-RAG for PCA: retrieval-time, per-principal document filtering driven by the PCA policy engine, with the filtering decision captured in the proof trace (provable: the model only saw authorized data).",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@atlasauth/pca": "0.1.0",
|
|
16
|
+
"@atlasauth/pca-policy-bridge": "0.1.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "^5.6.3",
|
|
20
|
+
"vitest": "^2.1.4"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc -p tsconfig.build.json",
|
|
31
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
32
|
+
"test": "vitest run"
|
|
33
|
+
}
|
|
6
34
|
}
|
package/README.md
DELETED