@opengeni/core 6.7.0 → 6.7.1-canary.41759707569001
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/domain/session-secret-redaction-matchers.d.ts +4 -0
- package/dist/domain/vaults/plain-field-hints.d.ts +17 -0
- package/dist/domain/vaults/provider-writes.d.ts +3 -1
- package/dist/index.js +81 -13
- package/dist/index.js.map +1 -1
- package/package.json +17 -16
- package/src/domain/session-secret-redaction-matchers.ts +5 -1
- package/src/domain/sessions.ts +16 -7
- package/src/domain/vaults/plain-field-hints.ts +40 -0
- package/src/domain/vaults/provider-writes.ts +26 -2
- package/src/domain/vaults/vault-service.ts +30 -2
|
@@ -21,6 +21,10 @@ export declare function secretRedactionReferenceLabel(reference: Pick<SecretRefe
|
|
|
21
21
|
* so a run with a one-character or all-blank "secret" can never rewrite
|
|
22
22
|
* everything. Also null for a value holding marker-shaped text, which the
|
|
23
23
|
* scrub could never find.
|
|
24
|
+
*
|
|
25
|
+
* A person asked for this value to be removed from stored history, so a
|
|
26
|
+
* weak value (a word, a host) is removed wherever it appears too, not only
|
|
27
|
+
* in credential positions as live masking does.
|
|
24
28
|
*/
|
|
25
29
|
export declare function secretRedactionMatcherForValue(value: string, label: string): SecretRedactionMatcher | null;
|
|
26
30
|
export declare function maskInPatternWindows(text: string, mask: (window: string) => string, windowChars?: number): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The save-time nudge for plain fields (docs/secrets.md, Field kinds). A
|
|
3
|
+
* value that looks like a secret in a field that would be saved as `text`
|
|
4
|
+
* is saved as `concealed` when nobody chose the kind (a new field whose
|
|
5
|
+
* default is text), and kept as text with a note when `text` was asked for,
|
|
6
|
+
* the field already is text, or it is a standard text field of the item's
|
|
7
|
+
* type (a login's `username`). Only saves that report notes (the agent's
|
|
8
|
+
* `secret_save`) are nudged: without `notes` the kind is unchanged, so a
|
|
9
|
+
* kind never changes silently. Nothing here refuses a save.
|
|
10
|
+
*/
|
|
11
|
+
import { type SecretSaveFieldNote, type VaultFieldKind } from "@opengeni/contracts";
|
|
12
|
+
export declare function plainFieldKind(input: {
|
|
13
|
+
name: string;
|
|
14
|
+
value: string;
|
|
15
|
+
kind: VaultFieldKind;
|
|
16
|
+
chosen: boolean;
|
|
17
|
+
}, notes: SecretSaveFieldNote[] | undefined): VaultFieldKind;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type VaultFieldInput, type VaultFieldKind, type VaultItemType, type VaultProviderOperations } from "@opengeni/contracts";
|
|
1
|
+
import { type SecretSaveFieldNote, type VaultFieldInput, type VaultFieldKind, type VaultItemType, type VaultProviderOperations } from "@opengeni/contracts";
|
|
2
2
|
import { VaultError, type Database, type VaultDbContext, type VaultFieldRow, type VaultRow } from "@opengeni/db";
|
|
3
3
|
import { type ProviderCallBudget, type VaultProvider, type VaultProviderRegistry } from "@opengeni/vaults";
|
|
4
4
|
import { type ProviderVaultSyncResult } from "./provider-sync.js";
|
|
@@ -96,6 +96,8 @@ export declare function writeProviderVaultItemOutcome(deps: ProviderWriteDeps, i
|
|
|
96
96
|
change: ProviderItemChange;
|
|
97
97
|
/** Receives the names of fields whose values were generated. */
|
|
98
98
|
generated?: string[];
|
|
99
|
+
/** Receives a note for each plain field whose value looks like a secret. */
|
|
100
|
+
fieldNotes?: SecretSaveFieldNote[];
|
|
99
101
|
}): Promise<ProviderWriteOutcome>;
|
|
100
102
|
/** Thrown when a confirmed provider write is not listed yet: it must not be saved again. */
|
|
101
103
|
export declare function savedNotListedError(vault: VaultRow, itemName: string, outcome: Extract<ProviderWriteOutcome, {
|
package/dist/index.js
CHANGED
|
@@ -7537,6 +7537,7 @@ import {
|
|
|
7537
7537
|
isDirectModelId,
|
|
7538
7538
|
MESSAGE_TIME_ZONE_METADATA_KEY,
|
|
7539
7539
|
messageSentByPerson,
|
|
7540
|
+
ModelPolicyRefusedError,
|
|
7540
7541
|
ModelUnavailableError,
|
|
7541
7542
|
normalizeMessageTimeZone
|
|
7542
7543
|
} from "@opengeni/contracts";
|
|
@@ -15952,8 +15953,10 @@ async function assertWorkspaceModelPolicyAllows(db, settings, workspaceId, model
|
|
|
15952
15953
|
chargesCredits: policyChargesCreditsForModel(settings, canonicalModel)
|
|
15953
15954
|
});
|
|
15954
15955
|
if (!verdict.allowed) {
|
|
15956
|
+
const message = verdict.reason === "credits" ? `model "${canonicalModel}" uses credits, which are turned off in this workspace. Choose a model paid by a subscription or API key, or ask a workspace admin to turn credits back on` : verdict.reason === "provider" ? `model "${canonicalModel}" is not allowed by this workspace's model policy: provider "${providerId}" is not in the allowed providers` : `model "${canonicalModel}" is not allowed by this workspace's model policy`;
|
|
15955
15957
|
throw new HTTPException24(422, {
|
|
15956
|
-
message
|
|
15958
|
+
message,
|
|
15959
|
+
cause: new ModelPolicyRefusedError(canonicalModel, verdict.reason, message)
|
|
15957
15960
|
});
|
|
15958
15961
|
}
|
|
15959
15962
|
}
|
|
@@ -17125,7 +17128,10 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
|
|
|
17125
17128
|
...claudeProviderAccountAuthoritySnapshot ? { claudeAuthoritySnapshot: claudeProviderAccountAuthoritySnapshot } : {}
|
|
17126
17129
|
});
|
|
17127
17130
|
if (!admissibleWorkspaceModel(selections, model)) {
|
|
17128
|
-
throw new HTTPException24(422, {
|
|
17131
|
+
throw new HTTPException24(422, {
|
|
17132
|
+
message: `model is not selectable: ${model}`,
|
|
17133
|
+
cause: new ModelUnavailableError(model)
|
|
17134
|
+
});
|
|
17129
17135
|
}
|
|
17130
17136
|
}
|
|
17131
17137
|
});
|
|
@@ -19693,7 +19699,7 @@ function secretRedactionMatcherForValue(value, label) {
|
|
|
19693
19699
|
if (containsSecretRedactionMarker(value)) return null;
|
|
19694
19700
|
if (secretValueForms(value, { minChars: SECRET_VALUE_MASK_MIN_CHARS }).length === 0) return null;
|
|
19695
19701
|
const marker = secretRedactionMarker(label);
|
|
19696
|
-
const masks = compileSecretValueMasks([{ value, label: marker }]);
|
|
19702
|
+
const masks = compileSecretValueMasks([{ value, label: marker }], { weakValues: "anywhere" });
|
|
19697
19703
|
return { marker, redact: (text5) => maskSecretValuesInText(text5, masks) };
|
|
19698
19704
|
}
|
|
19699
19705
|
var GITHUB_TOKEN = /^(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{30,255})$/u;
|
|
@@ -23774,6 +23780,32 @@ import {
|
|
|
23774
23780
|
readProviderItemInventory as readProviderItemInventory2
|
|
23775
23781
|
} from "@opengeni/vaults";
|
|
23776
23782
|
|
|
23783
|
+
// src/domain/vaults/plain-field-hints.ts
|
|
23784
|
+
import {
|
|
23785
|
+
plainFieldSecretHint
|
|
23786
|
+
} from "@opengeni/contracts";
|
|
23787
|
+
function plainFieldKind(input, notes) {
|
|
23788
|
+
if (notes === void 0 || input.kind !== "text") return input.kind;
|
|
23789
|
+
const hint = plainFieldSecretHint(input.name, input.value);
|
|
23790
|
+
if (!hint) return input.kind;
|
|
23791
|
+
if (input.chosen) {
|
|
23792
|
+
notes?.push({
|
|
23793
|
+
field: input.name,
|
|
23794
|
+
kind: "text",
|
|
23795
|
+
reason: hint.reason,
|
|
23796
|
+
message: `${hint.message} Kept as text; save it with kind "concealed" if it is a secret.`
|
|
23797
|
+
});
|
|
23798
|
+
return "text";
|
|
23799
|
+
}
|
|
23800
|
+
notes?.push({
|
|
23801
|
+
field: input.name,
|
|
23802
|
+
kind: "concealed",
|
|
23803
|
+
reason: hint.reason,
|
|
23804
|
+
message: `${hint.message} Saved as concealed; save it with kind "text" if it is not a secret.`
|
|
23805
|
+
});
|
|
23806
|
+
return "concealed";
|
|
23807
|
+
}
|
|
23808
|
+
|
|
23777
23809
|
// src/domain/vaults/typed-fields.ts
|
|
23778
23810
|
import {
|
|
23779
23811
|
VAULT_ITEM_TYPE_FIELDS,
|
|
@@ -24020,7 +24052,7 @@ function fileContent(input, current) {
|
|
|
24020
24052
|
const name = input.fileName ?? current?.fileName ?? input.name;
|
|
24021
24053
|
return { name, bytes };
|
|
24022
24054
|
}
|
|
24023
|
-
async function providerFieldValues(planned, resolveReference, generated) {
|
|
24055
|
+
async function providerFieldValues(type, planned, resolveReference, generated, fieldNotes) {
|
|
24024
24056
|
const writes = [];
|
|
24025
24057
|
for (const { input, base, kind, current } of planned) {
|
|
24026
24058
|
if (input.remove) {
|
|
@@ -24048,7 +24080,16 @@ async function providerFieldValues(planned, resolveReference, generated) {
|
|
|
24048
24080
|
}
|
|
24049
24081
|
value = value.trim();
|
|
24050
24082
|
}
|
|
24051
|
-
|
|
24083
|
+
const saved = plainFieldKind(
|
|
24084
|
+
{
|
|
24085
|
+
name: input.name,
|
|
24086
|
+
value,
|
|
24087
|
+
kind,
|
|
24088
|
+
chosen: input.kind !== void 0 || current !== void 0 || standardFieldKind(type, input.name) === "text"
|
|
24089
|
+
},
|
|
24090
|
+
fieldNotes
|
|
24091
|
+
);
|
|
24092
|
+
writes.push({ ...base, kind: saved, value });
|
|
24052
24093
|
}
|
|
24053
24094
|
return writes;
|
|
24054
24095
|
}
|
|
@@ -24173,7 +24214,13 @@ async function writeProviderVaultItemOutcome(deps, input) {
|
|
|
24173
24214
|
),
|
|
24174
24215
|
existing?.fields ?? []
|
|
24175
24216
|
);
|
|
24176
|
-
const fields = await providerFieldValues(
|
|
24217
|
+
const fields = await providerFieldValues(
|
|
24218
|
+
type,
|
|
24219
|
+
planned,
|
|
24220
|
+
deps.resolveReference,
|
|
24221
|
+
input.generated ?? [],
|
|
24222
|
+
input.fieldNotes
|
|
24223
|
+
);
|
|
24177
24224
|
const name = change.name ?? existing?.name ?? "";
|
|
24178
24225
|
const category = change.category !== void 0 ? change.category : existing?.category ?? null;
|
|
24179
24226
|
let written;
|
|
@@ -24610,7 +24657,7 @@ function defaultFieldKind(type, name) {
|
|
|
24610
24657
|
}
|
|
24611
24658
|
function createVaultService(deps) {
|
|
24612
24659
|
const clock = deps.clock ?? systemSecretClock;
|
|
24613
|
-
async function fieldWrite(input, existing, type, resolveReference, generated) {
|
|
24660
|
+
async function fieldWrite(input, existing, type, resolveReference, generated, fieldNotes) {
|
|
24614
24661
|
const current = existing?.fields.find(
|
|
24615
24662
|
(field) => input.fieldId !== void 0 && field.id === input.fieldId || secretNameKey5(field.name) === secretNameKey5(input.name)
|
|
24616
24663
|
);
|
|
@@ -24641,6 +24688,15 @@ function createVaultService(deps) {
|
|
|
24641
24688
|
plaintext = input.value ?? "";
|
|
24642
24689
|
size = utf8Size(plaintext);
|
|
24643
24690
|
}
|
|
24691
|
+
kind = plainFieldKind(
|
|
24692
|
+
{
|
|
24693
|
+
name: input.name,
|
|
24694
|
+
value: plaintext,
|
|
24695
|
+
kind,
|
|
24696
|
+
chosen: input.kind !== void 0 || current !== void 0 || standardFieldKind(type, input.name) === "text"
|
|
24697
|
+
},
|
|
24698
|
+
fieldNotes
|
|
24699
|
+
);
|
|
24644
24700
|
if (kind === "totp") {
|
|
24645
24701
|
if (!isValidTotpInput3(plaintext)) {
|
|
24646
24702
|
throw new VaultError4(
|
|
@@ -24706,7 +24762,7 @@ function createVaultService(deps) {
|
|
|
24706
24762
|
if (value.material.type === "bytes") return Buffer.from(value.material.value).toString("utf8");
|
|
24707
24763
|
return totpCodeSync(value.material.params, clock.now());
|
|
24708
24764
|
}
|
|
24709
|
-
async function itemWrite(req, existing, resolveReference, createdBy, generated = []) {
|
|
24765
|
+
async function itemWrite(req, existing, resolveReference, createdBy, generated = [], fieldNotes) {
|
|
24710
24766
|
const write = { createdByKind: createdBy };
|
|
24711
24767
|
if (req.name !== void 0) write.name = req.name;
|
|
24712
24768
|
if (req.type !== void 0) write.type = req.type;
|
|
@@ -24719,7 +24775,9 @@ function createVaultService(deps) {
|
|
|
24719
24775
|
const fields = await prepareTypedFields(type, req.fields, resolveReference, generated);
|
|
24720
24776
|
write.fields = [];
|
|
24721
24777
|
for (const field of fields) {
|
|
24722
|
-
write.fields.push(
|
|
24778
|
+
write.fields.push(
|
|
24779
|
+
await fieldWrite(field, existing, type, resolveReference, generated, fieldNotes)
|
|
24780
|
+
);
|
|
24723
24781
|
}
|
|
24724
24782
|
}
|
|
24725
24783
|
return write;
|
|
@@ -25498,6 +25556,8 @@ function createVaultService(deps) {
|
|
|
25498
25556
|
fields.unshift({ name: "username", kind: "text", value: input.username });
|
|
25499
25557
|
}
|
|
25500
25558
|
const generated = [];
|
|
25559
|
+
const fieldNotes = [];
|
|
25560
|
+
const notes = () => fieldNotes.length > 0 ? { fieldNotes } : {};
|
|
25501
25561
|
if (vault.source !== "opengeni") {
|
|
25502
25562
|
const itemId = await writeProviderVaultItem(
|
|
25503
25563
|
{
|
|
@@ -25523,14 +25583,16 @@ function createVaultService(deps) {
|
|
|
25523
25583
|
...input.websites !== void 0 ? { websites: input.websites } : {},
|
|
25524
25584
|
fields
|
|
25525
25585
|
},
|
|
25526
|
-
generated
|
|
25586
|
+
generated,
|
|
25587
|
+
fieldNotes
|
|
25527
25588
|
}
|
|
25528
25589
|
);
|
|
25529
25590
|
const saved = await getVaultItem2(deps.db, context, { itemId });
|
|
25530
25591
|
return {
|
|
25531
25592
|
item: toVaultItemSummary(saved, key()),
|
|
25532
25593
|
references: vaultItemReferences(saved),
|
|
25533
|
-
generatedFields: generated
|
|
25594
|
+
generatedFields: generated,
|
|
25595
|
+
...notes()
|
|
25534
25596
|
};
|
|
25535
25597
|
}
|
|
25536
25598
|
const write = await itemWrite(
|
|
@@ -25543,7 +25605,8 @@ function createVaultService(deps) {
|
|
|
25543
25605
|
fullExisting,
|
|
25544
25606
|
(raw) => resolveTextReference(principal, raw, "secret_save"),
|
|
25545
25607
|
"agent",
|
|
25546
|
-
generated
|
|
25608
|
+
generated,
|
|
25609
|
+
fieldNotes
|
|
25547
25610
|
);
|
|
25548
25611
|
const row = await upsertVaultItem(
|
|
25549
25612
|
deps.db,
|
|
@@ -25551,7 +25614,12 @@ function createVaultService(deps) {
|
|
|
25551
25614
|
fullExisting ? { ...write, itemId: fullExisting.id } : { ...write, vaultId: vault.id, mode: "create" }
|
|
25552
25615
|
);
|
|
25553
25616
|
const summary = toVaultItemSummary(row, key());
|
|
25554
|
-
return {
|
|
25617
|
+
return {
|
|
25618
|
+
item: summary,
|
|
25619
|
+
references: vaultItemReferences(row),
|
|
25620
|
+
generatedFields: generated,
|
|
25621
|
+
...notes()
|
|
25622
|
+
};
|
|
25555
25623
|
},
|
|
25556
25624
|
async captureForAgent(principal, input) {
|
|
25557
25625
|
if (principal.kind !== "attempt") {
|