@automagik/omni 2.260718.4 → 2.260718.6
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.js +34 -7
- package/dist/server/index.js +128 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -73282,6 +73282,38 @@ class ApiKeyService {
|
|
|
73282
73282
|
if (options.name !== undefined && await this.isPrimaryKey(id)) {
|
|
73283
73283
|
throw new Error("Cannot rename primary API key");
|
|
73284
73284
|
}
|
|
73285
|
+
const updates = this.buildUpdateValues(options);
|
|
73286
|
+
const [updated] = await this.db.update(apiKeys).set(updates).where(eq2(apiKeys.id, id)).returning();
|
|
73287
|
+
if (updated) {
|
|
73288
|
+
await apiKeyCache.delete(CacheKeys.apiKey(updated.keyHash));
|
|
73289
|
+
log20.info("API key updated", { id, fields: Object.keys(options) });
|
|
73290
|
+
}
|
|
73291
|
+
return updated ?? null;
|
|
73292
|
+
}
|
|
73293
|
+
async updateWithAuthorityGuard(id, options, guard) {
|
|
73294
|
+
const result = await this.db.transaction(async (tx2) => {
|
|
73295
|
+
const [current] = await tx2.select().from(apiKeys).where(eq2(apiKeys.id, id)).limit(1).for("update");
|
|
73296
|
+
if (!current)
|
|
73297
|
+
return { status: "not_found" };
|
|
73298
|
+
if (options.name !== undefined && current.name === PRIMARY_KEY_NAME) {
|
|
73299
|
+
throw new Error("Cannot rename primary API key");
|
|
73300
|
+
}
|
|
73301
|
+
const updates = this.buildUpdateValues(options);
|
|
73302
|
+
const next = { ...current, ...updates };
|
|
73303
|
+
if (!await guard(current, next))
|
|
73304
|
+
return { status: "denied" };
|
|
73305
|
+
const [updated] = await tx2.update(apiKeys).set(updates).where(eq2(apiKeys.id, id)).returning();
|
|
73306
|
+
if (!updated)
|
|
73307
|
+
return { status: "not_found" };
|
|
73308
|
+
return { status: "updated", key: updated };
|
|
73309
|
+
});
|
|
73310
|
+
if (result.status === "updated") {
|
|
73311
|
+
await apiKeyCache.delete(CacheKeys.apiKey(result.key.keyHash));
|
|
73312
|
+
log20.info("API key updated", { id, fields: Object.keys(options) });
|
|
73313
|
+
}
|
|
73314
|
+
return result;
|
|
73315
|
+
}
|
|
73316
|
+
buildUpdateValues(options) {
|
|
73285
73317
|
const updates = { updatedAt: new Date };
|
|
73286
73318
|
if (options.name !== undefined)
|
|
73287
73319
|
updates.name = options.name;
|
|
@@ -73304,12 +73336,7 @@ class ApiKeyService {
|
|
|
73304
73336
|
if (options.contextInstanceId !== undefined || options.contextChatId !== undefined || options.contextMessageId !== undefined) {
|
|
73305
73337
|
updates.contextUpdatedAt = new Date;
|
|
73306
73338
|
}
|
|
73307
|
-
|
|
73308
|
-
if (updated) {
|
|
73309
|
-
await apiKeyCache.delete(CacheKeys.apiKey(updated.keyHash));
|
|
73310
|
-
log20.info("API key updated", { id, fields: Object.keys(options) });
|
|
73311
|
-
}
|
|
73312
|
-
return updated ?? null;
|
|
73339
|
+
return updates;
|
|
73313
73340
|
}
|
|
73314
73341
|
async list() {
|
|
73315
73342
|
return this.db.select().from(apiKeys).orderBy(apiKeys.createdAt);
|
|
@@ -125164,7 +125191,7 @@ import { fileURLToPath } from "url";
|
|
|
125164
125191
|
// package.json
|
|
125165
125192
|
var package_default = {
|
|
125166
125193
|
name: "@automagik/omni",
|
|
125167
|
-
version: "2.260718.
|
|
125194
|
+
version: "2.260718.6",
|
|
125168
125195
|
description: "LLM-optimized CLI for Omni",
|
|
125169
125196
|
type: "module",
|
|
125170
125197
|
bin: {
|
package/dist/server/index.js
CHANGED
|
@@ -227026,7 +227026,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
227026
227026
|
var require_package7 = __commonJS((exports, module) => {
|
|
227027
227027
|
module.exports = {
|
|
227028
227028
|
name: "@omni/api",
|
|
227029
|
-
version: "2.260718.
|
|
227029
|
+
version: "2.260718.6",
|
|
227030
227030
|
type: "module",
|
|
227031
227031
|
exports: {
|
|
227032
227032
|
".": {
|
|
@@ -285713,6 +285713,38 @@ class ApiKeyService {
|
|
|
285713
285713
|
if (options.name !== undefined && await this.isPrimaryKey(id)) {
|
|
285714
285714
|
throw new Error("Cannot rename primary API key");
|
|
285715
285715
|
}
|
|
285716
|
+
const updates = this.buildUpdateValues(options);
|
|
285717
|
+
const [updated] = await this.db.update(apiKeys).set(updates).where(eq(apiKeys.id, id)).returning();
|
|
285718
|
+
if (updated) {
|
|
285719
|
+
await apiKeyCache.delete(CacheKeys.apiKey(updated.keyHash));
|
|
285720
|
+
log58.info("API key updated", { id, fields: Object.keys(options) });
|
|
285721
|
+
}
|
|
285722
|
+
return updated ?? null;
|
|
285723
|
+
}
|
|
285724
|
+
async updateWithAuthorityGuard(id, options, guard) {
|
|
285725
|
+
const result = await this.db.transaction(async (tx) => {
|
|
285726
|
+
const [current] = await tx.select().from(apiKeys).where(eq(apiKeys.id, id)).limit(1).for("update");
|
|
285727
|
+
if (!current)
|
|
285728
|
+
return { status: "not_found" };
|
|
285729
|
+
if (options.name !== undefined && current.name === PRIMARY_KEY_NAME) {
|
|
285730
|
+
throw new Error("Cannot rename primary API key");
|
|
285731
|
+
}
|
|
285732
|
+
const updates = this.buildUpdateValues(options);
|
|
285733
|
+
const next = { ...current, ...updates };
|
|
285734
|
+
if (!await guard(current, next))
|
|
285735
|
+
return { status: "denied" };
|
|
285736
|
+
const [updated] = await tx.update(apiKeys).set(updates).where(eq(apiKeys.id, id)).returning();
|
|
285737
|
+
if (!updated)
|
|
285738
|
+
return { status: "not_found" };
|
|
285739
|
+
return { status: "updated", key: updated };
|
|
285740
|
+
});
|
|
285741
|
+
if (result.status === "updated") {
|
|
285742
|
+
await apiKeyCache.delete(CacheKeys.apiKey(result.key.keyHash));
|
|
285743
|
+
log58.info("API key updated", { id, fields: Object.keys(options) });
|
|
285744
|
+
}
|
|
285745
|
+
return result;
|
|
285746
|
+
}
|
|
285747
|
+
buildUpdateValues(options) {
|
|
285716
285748
|
const updates = { updatedAt: new Date };
|
|
285717
285749
|
if (options.name !== undefined)
|
|
285718
285750
|
updates.name = options.name;
|
|
@@ -285735,12 +285767,7 @@ class ApiKeyService {
|
|
|
285735
285767
|
if (options.contextInstanceId !== undefined || options.contextChatId !== undefined || options.contextMessageId !== undefined) {
|
|
285736
285768
|
updates.contextUpdatedAt = new Date;
|
|
285737
285769
|
}
|
|
285738
|
-
|
|
285739
|
-
if (updated) {
|
|
285740
|
-
await apiKeyCache.delete(CacheKeys.apiKey(updated.keyHash));
|
|
285741
|
-
log58.info("API key updated", { id, fields: Object.keys(options) });
|
|
285742
|
-
}
|
|
285743
|
-
return updated ?? null;
|
|
285770
|
+
return updates;
|
|
285744
285771
|
}
|
|
285745
285772
|
async list() {
|
|
285746
285773
|
return this.db.select().from(apiKeys).orderBy(apiKeys.createdAt);
|
|
@@ -357988,11 +358015,62 @@ function enforceScopeCeiling(c, requestedScopes) {
|
|
|
357988
358015
|
}
|
|
357989
358016
|
}, 403);
|
|
357990
358017
|
}
|
|
357991
|
-
function
|
|
357992
|
-
|
|
357993
|
-
|
|
358018
|
+
function isStringArray(value) {
|
|
358019
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
358020
|
+
}
|
|
358021
|
+
function normalizeInstanceIds(values2) {
|
|
358022
|
+
return new Set(values2.map((value) => value.toLowerCase()));
|
|
358023
|
+
}
|
|
358024
|
+
function intersectAuthorities(left, right) {
|
|
358025
|
+
if (left === null)
|
|
358026
|
+
return right;
|
|
358027
|
+
if (right === null)
|
|
358028
|
+
return left;
|
|
358029
|
+
return new Set([...left].filter((instanceId) => right.has(instanceId)));
|
|
358030
|
+
}
|
|
358031
|
+
function deriveInstanceAuthorities(input) {
|
|
358032
|
+
if (input.instanceIds !== null && !isStringArray(input.instanceIds))
|
|
358033
|
+
return null;
|
|
358034
|
+
if (input.instanceAllowlist !== undefined && !isStringArray(input.instanceAllowlist))
|
|
358035
|
+
return null;
|
|
358036
|
+
if (input.profile !== undefined && input.profile !== null && (typeof input.profile !== "string" || !KNOWN_API_KEY_PROFILES.has(input.profile))) {
|
|
357994
358037
|
return null;
|
|
357995
|
-
|
|
358038
|
+
}
|
|
358039
|
+
const legacy = input.instanceIds === null ? null : normalizeInstanceIds(input.instanceIds);
|
|
358040
|
+
const legacyEmptyInactive = input.instanceIds === null || input.instanceIds.length === 0 ? null : legacy;
|
|
358041
|
+
const instanceAllowlist = input.instanceAllowlist ?? [];
|
|
358042
|
+
const profileAware = isLockActive(input.profile, "instanceAllowlist", instanceAllowlist) ? normalizeInstanceIds(instanceAllowlist) : null;
|
|
358043
|
+
return {
|
|
358044
|
+
legacy,
|
|
358045
|
+
legacyEmptyInactive,
|
|
358046
|
+
effective: intersectAuthorities(legacy, profileAware),
|
|
358047
|
+
profileAware
|
|
358048
|
+
};
|
|
358049
|
+
}
|
|
358050
|
+
function isAuthoritySubset(requested, allowed) {
|
|
358051
|
+
if (allowed === null)
|
|
358052
|
+
return true;
|
|
358053
|
+
if (requested === null)
|
|
358054
|
+
return false;
|
|
358055
|
+
return [...requested].every((instanceId) => allowed.has(instanceId));
|
|
358056
|
+
}
|
|
358057
|
+
function enforceInstanceCeiling(c, requestedAuthority) {
|
|
358058
|
+
const apiKey = c.get("apiKey");
|
|
358059
|
+
if (!apiKey) {
|
|
358060
|
+
return c.json({
|
|
358061
|
+
error: {
|
|
358062
|
+
code: "FORBIDDEN",
|
|
358063
|
+
message: "Cannot grant instance access that exceeds the caller's own."
|
|
358064
|
+
}
|
|
358065
|
+
}, 403);
|
|
358066
|
+
}
|
|
358067
|
+
const callerAuthorities = deriveInstanceAuthorities({
|
|
358068
|
+
instanceIds: apiKey.instanceIds,
|
|
358069
|
+
profile: apiKey.profile,
|
|
358070
|
+
instanceAllowlist: apiKey.instanceAllowlist
|
|
358071
|
+
});
|
|
358072
|
+
const childAuthorities = deriveInstanceAuthorities(requestedAuthority);
|
|
358073
|
+
const exceedsCaller = callerAuthorities === null || childAuthorities === null || !isAuthoritySubset(childAuthorities.legacy, callerAuthorities.legacy) || !isAuthoritySubset(childAuthorities.legacyEmptyInactive, callerAuthorities.legacyEmptyInactive) || !isAuthoritySubset(childAuthorities.profileAware, callerAuthorities.profileAware) || !isAuthoritySubset(childAuthorities.effective, callerAuthorities.effective);
|
|
357996
358074
|
if (!exceedsCaller)
|
|
357997
358075
|
return null;
|
|
357998
358076
|
return c.json({
|
|
@@ -358016,7 +358094,11 @@ async function handleProfileCreate(c, data, services) {
|
|
|
358016
358094
|
const ceilingDenied = enforceScopeCeiling(c, resolved.scopes);
|
|
358017
358095
|
if (ceilingDenied)
|
|
358018
358096
|
return ceilingDenied;
|
|
358019
|
-
const instanceCeilingDenied = enforceInstanceCeiling(c,
|
|
358097
|
+
const instanceCeilingDenied = enforceInstanceCeiling(c, {
|
|
358098
|
+
instanceIds: data.instanceIds ?? null,
|
|
358099
|
+
profile: resolved.profile,
|
|
358100
|
+
instanceAllowlist: resolved.instanceAllowlist
|
|
358101
|
+
});
|
|
358020
358102
|
if (instanceCeilingDenied)
|
|
358021
358103
|
return instanceCeilingDenied;
|
|
358022
358104
|
const result = await services.apiKeys.create({
|
|
@@ -358054,7 +358136,11 @@ async function handleLegacyCreate(c, data, services) {
|
|
|
358054
358136
|
const ceilingDenied = enforceScopeCeiling(c, data.scopes);
|
|
358055
358137
|
if (ceilingDenied)
|
|
358056
358138
|
return ceilingDenied;
|
|
358057
|
-
const instanceCeilingDenied = enforceInstanceCeiling(c,
|
|
358139
|
+
const instanceCeilingDenied = enforceInstanceCeiling(c, {
|
|
358140
|
+
instanceIds: data.instanceIds ?? null,
|
|
358141
|
+
profile: null,
|
|
358142
|
+
instanceAllowlist: []
|
|
358143
|
+
});
|
|
358058
358144
|
if (instanceCeilingDenied)
|
|
358059
358145
|
return instanceCeilingDenied;
|
|
358060
358146
|
const result = await services.apiKeys.create({
|
|
@@ -358068,13 +358154,14 @@ async function handleLegacyCreate(c, data, services) {
|
|
|
358068
358154
|
});
|
|
358069
358155
|
return c.json({ data: { ...result.key, plainTextKey: result.plainTextKey } }, 201);
|
|
358070
358156
|
}
|
|
358071
|
-
var keysRoutes, NON_ADMIN_PROFILES, profileOverridesSchema, createKeySchema, updateKeySchema, revokeKeySchema, listQuerySchema13, auditQuerySchema;
|
|
358157
|
+
var keysRoutes, NON_ADMIN_PROFILES, KNOWN_API_KEY_PROFILES, profileOverridesSchema, createKeySchema, updateKeySchema, revokeKeySchema, listQuerySchema13, auditQuerySchema;
|
|
358072
358158
|
var init_keys = __esm(() => {
|
|
358073
358159
|
init_dist6();
|
|
358074
358160
|
init_dist2();
|
|
358075
358161
|
init_zod();
|
|
358076
358162
|
init_resolve_profile();
|
|
358077
358163
|
init_signed_host_scope_context();
|
|
358164
|
+
init_scope_enforcer();
|
|
358078
358165
|
init_date_query();
|
|
358079
358166
|
init_api_keys();
|
|
358080
358167
|
keysRoutes = new Hono2;
|
|
@@ -358087,6 +358174,7 @@ var init_keys = __esm(() => {
|
|
|
358087
358174
|
"console-operator",
|
|
358088
358175
|
"console-admin"
|
|
358089
358176
|
];
|
|
358177
|
+
KNOWN_API_KEY_PROFILES = new Set(["admin", ...NON_ADMIN_PROFILES]);
|
|
358090
358178
|
profileOverridesSchema = exports_external.object({
|
|
358091
358179
|
add: exports_external.array(exports_external.string()).optional(),
|
|
358092
358180
|
remove: exports_external.array(exports_external.string()).optional(),
|
|
@@ -358179,21 +358267,33 @@ var init_keys = __esm(() => {
|
|
|
358179
358267
|
const id = c.req.param("id");
|
|
358180
358268
|
const data = c.req.valid("json");
|
|
358181
358269
|
const services = c.get("services");
|
|
358182
|
-
|
|
358183
|
-
|
|
358184
|
-
|
|
358185
|
-
|
|
358186
|
-
}
|
|
358187
|
-
if (data.instanceIds !== undefined) {
|
|
358188
|
-
const instanceCeilingDenied = enforceInstanceCeiling(c, data.instanceIds);
|
|
358189
|
-
if (instanceCeilingDenied)
|
|
358190
|
-
return instanceCeilingDenied;
|
|
358191
|
-
}
|
|
358270
|
+
const updateOptions = {
|
|
358271
|
+
...data,
|
|
358272
|
+
expiresAt: data.expiresAt === null ? null : data.expiresAt ? new Date(data.expiresAt) : undefined
|
|
358273
|
+
};
|
|
358192
358274
|
try {
|
|
358193
|
-
|
|
358194
|
-
|
|
358195
|
-
|
|
358196
|
-
|
|
358275
|
+
if (data.instanceIds !== undefined || data.scopes !== undefined) {
|
|
358276
|
+
let authorityDenied;
|
|
358277
|
+
const result = await services.apiKeys.updateWithAuthorityGuard(id, updateOptions, (_current, next) => {
|
|
358278
|
+
authorityDenied = enforceScopeCeiling(c, next.scopes);
|
|
358279
|
+
if (authorityDenied)
|
|
358280
|
+
return false;
|
|
358281
|
+
authorityDenied = enforceInstanceCeiling(c, {
|
|
358282
|
+
instanceIds: next.instanceIds,
|
|
358283
|
+
profile: next.profile,
|
|
358284
|
+
instanceAllowlist: next.instanceAllowlist
|
|
358285
|
+
});
|
|
358286
|
+
return authorityDenied == null;
|
|
358287
|
+
});
|
|
358288
|
+
if (result.status === "denied") {
|
|
358289
|
+
return authorityDenied ?? c.json({ error: { code: "FORBIDDEN", message: "API key authority exceeds caller authority" } }, 403);
|
|
358290
|
+
}
|
|
358291
|
+
if (result.status === "not_found") {
|
|
358292
|
+
return c.json({ error: { code: "NOT_FOUND", message: "API key not found" } }, 404);
|
|
358293
|
+
}
|
|
358294
|
+
return c.json({ data: result.key });
|
|
358295
|
+
}
|
|
358296
|
+
const updated = await services.apiKeys.update(id, updateOptions);
|
|
358197
358297
|
if (!updated) {
|
|
358198
358298
|
return c.json({ error: { code: "NOT_FOUND", message: "API key not found" } }, 404);
|
|
358199
358299
|
}
|