@envseal/protocol 0.1.5 → 0.1.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/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const SEP_ERROR_CODES: readonly ["SEP_UNKNOWN_KEY", "SEP_NOT_DECLARED", "SEP_NO_INTERACTIVE_SURFACE", "SEP_TICKET_EXPIRED", "SEP_TICKET_UNKNOWN", "SEP_USER_CANCELLED", "SEP_FORMAT_INVALID", "SEP_SINK_UNAVAILABLE", "SEP_SINK_WRITE_FAILED", "SEP_PROBE_NOT_APPROVED", "SEP_VALUE_IN_REQUEST", "SEP_GITIGNORE_UNSAFE", "SEP_CONFIRMATION_DENIED", "SEP_RATE_LIMITED", "SEP_TARGET_CHANGED", "SEP_PATTERN_UNSAFE", "SEP_KEYS_MISSING"];
1
+ export declare const SEP_ERROR_CODES: readonly ["SEP_UNKNOWN_KEY", "SEP_NOT_DECLARED", "SEP_NO_INTERACTIVE_SURFACE", "SEP_TICKET_EXPIRED", "SEP_TICKET_UNKNOWN", "SEP_USER_CANCELLED", "SEP_FORMAT_INVALID", "SEP_SINK_UNAVAILABLE", "SEP_SINK_WRITE_FAILED", "SEP_PROBE_NOT_APPROVED", "SEP_VALUE_IN_REQUEST", "SEP_GITIGNORE_UNSAFE", "SEP_CONFIRMATION_DENIED", "SEP_RATE_LIMITED", "SEP_TARGET_CHANGED", "SEP_EGRESS_DENIED", "SEP_PATTERN_UNSAFE", "SEP_KEYS_MISSING"];
2
2
  export type SepErrorCode = (typeof SEP_ERROR_CODES)[number];
3
3
  export interface SepErrorDefaults {
4
4
  retriable: boolean;
package/dist/errors.js CHANGED
@@ -14,6 +14,7 @@ export const SEP_ERROR_CODES = [
14
14
  'SEP_CONFIRMATION_DENIED',
15
15
  'SEP_RATE_LIMITED',
16
16
  'SEP_TARGET_CHANGED',
17
+ 'SEP_EGRESS_DENIED',
17
18
  'SEP_PATTERN_UNSAFE',
18
19
  'SEP_KEYS_MISSING',
19
20
  ];
@@ -79,6 +80,11 @@ export const SEP_ERROR_DEFAULTS = {
79
80
  userMessage: 'The program to run changed on disk after you approved it. Nothing was executed. ' +
80
81
  'Re-run the command to review the current content and approve it again.',
81
82
  },
83
+ SEP_EGRESS_DENIED: {
84
+ retriable: false,
85
+ userMessage: 'This project uses an egress allowlist, and the command targets a host that is not on it. ' +
86
+ 'Nothing was executed or sent. To allow the host, add it to policy.egress.allow in env.schema.jsonc.',
87
+ },
82
88
  SEP_PATTERN_UNSAFE: {
83
89
  retriable: false,
84
90
  userMessage: 'The declared format.pattern is unsafe or too complex. Use a shorter, bounded pattern (for example ^sk-[A-Za-z0-9]{20,80}$).',
package/dist/schemas.d.ts CHANGED
@@ -188,6 +188,36 @@ export declare const ManifestEntry: z.ZodEffects<z.ZodObject<{
188
188
  } | undefined;
189
189
  }>;
190
190
  export type ManifestEntry = z.infer<typeof ManifestEntry>;
191
+ /**
192
+ * policy.egress — declarative egress restriction for env_use (SEP/1 minor
193
+ * addition). mode 'warn' (default when policy is absent) preserves historical
194
+ * behavior: network-touching commands draw an extra warning in the consent
195
+ * dialog. mode 'allowlist' hard-refuses any network command whose target host
196
+ * is not listed, BEFORE any dialog opens. The override path is deliberately
197
+ * editing this file rather than clicking a dialog: a prompt-injected agent
198
+ * cannot talk the user past a control that does not exist mid-flow.
199
+ *
200
+ * Allow entries are hostnames or single-label wildcards ('*.openai.com').
201
+ * URLs, ports, and schemes are rejected here so the enforcement layer can
202
+ * trust entries blindly.
203
+ */
204
+ export declare const EgressPolicy: z.ZodEffects<z.ZodObject<{
205
+ mode: z.ZodEnum<["warn", "allowlist"]>;
206
+ allow: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
207
+ }, "strict", z.ZodTypeAny, {
208
+ mode: "warn" | "allowlist";
209
+ allow: string[];
210
+ }, {
211
+ mode: "warn" | "allowlist";
212
+ allow?: string[] | undefined;
213
+ }>, {
214
+ mode: "warn" | "allowlist";
215
+ allow: string[];
216
+ }, {
217
+ mode: "warn" | "allowlist";
218
+ allow?: string[] | undefined;
219
+ }>;
220
+ export type EgressPolicy = z.infer<typeof EgressPolicy>;
191
221
  export declare const Manifest: z.ZodObject<{
192
222
  $schema: z.ZodOptional<z.ZodString>;
193
223
  version: z.ZodLiteral<1>;
@@ -375,6 +405,34 @@ export declare const Manifest: z.ZodObject<{
375
405
  maxAgeDays: number;
376
406
  } | undefined;
377
407
  }>, "many">>;
408
+ policy: z.ZodOptional<z.ZodObject<{
409
+ egress: z.ZodEffects<z.ZodObject<{
410
+ mode: z.ZodEnum<["warn", "allowlist"]>;
411
+ allow: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
412
+ }, "strict", z.ZodTypeAny, {
413
+ mode: "warn" | "allowlist";
414
+ allow: string[];
415
+ }, {
416
+ mode: "warn" | "allowlist";
417
+ allow?: string[] | undefined;
418
+ }>, {
419
+ mode: "warn" | "allowlist";
420
+ allow: string[];
421
+ }, {
422
+ mode: "warn" | "allowlist";
423
+ allow?: string[] | undefined;
424
+ }>;
425
+ }, "strict", z.ZodTypeAny, {
426
+ egress: {
427
+ mode: "warn" | "allowlist";
428
+ allow: string[];
429
+ };
430
+ }, {
431
+ egress: {
432
+ mode: "warn" | "allowlist";
433
+ allow?: string[] | undefined;
434
+ };
435
+ }>>;
378
436
  }, "strict", z.ZodTypeAny, {
379
437
  entries: {
380
438
  key: string;
@@ -408,6 +466,12 @@ export declare const Manifest: z.ZodObject<{
408
466
  }[];
409
467
  version: 1;
410
468
  $schema?: string | undefined;
469
+ policy?: {
470
+ egress: {
471
+ mode: "warn" | "allowlist";
472
+ allow: string[];
473
+ };
474
+ } | undefined;
411
475
  }, {
412
476
  version: 1;
413
477
  entries?: {
@@ -441,6 +505,12 @@ export declare const Manifest: z.ZodObject<{
441
505
  } | undefined;
442
506
  }[] | undefined;
443
507
  $schema?: string | undefined;
508
+ policy?: {
509
+ egress: {
510
+ mode: "warn" | "allowlist";
511
+ allow?: string[] | undefined;
512
+ };
513
+ } | undefined;
444
514
  }>;
445
515
  export type Manifest = z.infer<typeof Manifest>;
446
516
  export declare const KeyStatus: z.ZodObject<{
package/dist/schemas.js CHANGED
@@ -253,11 +253,50 @@ export const ManifestEntry = z
253
253
  });
254
254
  }
255
255
  });
256
+ /**
257
+ * policy.egress — declarative egress restriction for env_use (SEP/1 minor
258
+ * addition). mode 'warn' (default when policy is absent) preserves historical
259
+ * behavior: network-touching commands draw an extra warning in the consent
260
+ * dialog. mode 'allowlist' hard-refuses any network command whose target host
261
+ * is not listed, BEFORE any dialog opens. The override path is deliberately
262
+ * editing this file rather than clicking a dialog: a prompt-injected agent
263
+ * cannot talk the user past a control that does not exist mid-flow.
264
+ *
265
+ * Allow entries are hostnames or single-label wildcards ('*.openai.com').
266
+ * URLs, ports, and schemes are rejected here so the enforcement layer can
267
+ * trust entries blindly.
268
+ */
269
+ export const EgressPolicy = z
270
+ .object({
271
+ mode: z.enum(['warn', 'allowlist']),
272
+ allow: z.array(z.string()).default([]),
273
+ })
274
+ .strict()
275
+ .superRefine((policy, ctx) => {
276
+ if (policy.mode === 'allowlist' && policy.allow.length === 0) {
277
+ ctx.addIssue({
278
+ code: z.ZodIssueCode.custom,
279
+ path: ['allow'],
280
+ message: 'mode "allowlist" requires at least one entry in allow',
281
+ });
282
+ }
283
+ const HOST_PATTERN = /^(\*\.)?[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
284
+ for (const [i, entry] of policy.allow.entries()) {
285
+ if (!HOST_PATTERN.test(entry)) {
286
+ ctx.addIssue({
287
+ code: z.ZodIssueCode.custom,
288
+ path: ['allow', i],
289
+ message: 'allow entries must be hostnames or "*.suffix" wildcards — no URLs, ports, schemes, or paths',
290
+ });
291
+ }
292
+ }
293
+ });
256
294
  export const Manifest = z
257
295
  .object({
258
296
  $schema: z.string().optional(),
259
297
  version: z.literal(1),
260
298
  entries: z.array(ManifestEntry).default([]),
299
+ policy: z.object({ egress: EgressPolicy }).strict().optional(),
261
300
  })
262
301
  .strict();
263
302
  export const KeyStatus = z
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envseal/protocol",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",