@orbitpanel/cli 1.5.0 → 1.5.1
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.
|
@@ -8,17 +8,33 @@
|
|
|
8
8
|
* DESIGN:
|
|
9
9
|
* - Centralizzata: una sola funzione, chiamata dal router
|
|
10
10
|
* - Fail-closed: se non puoi chiedere, non eseguire
|
|
11
|
-
* -
|
|
11
|
+
* - Policy esplicita: ogni comando sensibile ha risk level e reason
|
|
12
|
+
* - Audit: --force su critical viene loggato in ~/.orbit/force.log
|
|
12
13
|
* - Override esplicito: --force bypassa la guard
|
|
13
14
|
*/
|
|
14
|
-
import type { ContextHealth } from '../types.js';
|
|
15
|
+
import type { ContextHealth, ContextHealthLevel } from '../types.js';
|
|
16
|
+
export interface SensitiveCommandPolicy {
|
|
17
|
+
/** Primary command name (e.g. '/report') */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Aliases (e.g. ['/r']) */
|
|
20
|
+
aliases: string[];
|
|
21
|
+
/** Risk level — determines guard behavior */
|
|
22
|
+
risk: 'low' | 'medium' | 'high';
|
|
23
|
+
/** Human-readable reason why this command is sensitive */
|
|
24
|
+
reason: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Centralized policy registry for sensitive commands.
|
|
28
|
+
* Single source of truth — add new commands here.
|
|
29
|
+
*/
|
|
30
|
+
export declare const COMMAND_POLICIES: readonly SensitiveCommandPolicy[];
|
|
15
31
|
/**
|
|
16
|
-
*
|
|
17
|
-
* Each entry is a prefix — e.g. '/link' matches '/link site_123'.
|
|
32
|
+
* Find the policy for a given command. Returns null for non-sensitive commands.
|
|
18
33
|
*/
|
|
19
|
-
export declare
|
|
34
|
+
export declare function getCommandPolicy(cmd: string): SensitiveCommandPolicy | null;
|
|
20
35
|
/**
|
|
21
36
|
* Check if a command is sensitive (requires guard on critical context).
|
|
37
|
+
* Backward-compatible wrapper around getCommandPolicy.
|
|
22
38
|
*/
|
|
23
39
|
export declare function isSensitiveCommand(cmd: string): boolean;
|
|
24
40
|
/**
|
|
@@ -41,6 +57,20 @@ export declare function formatGuardMessage(health: ContextHealth): string;
|
|
|
41
57
|
* Format the blocked message shown in non-TTY when command is blocked.
|
|
42
58
|
*/
|
|
43
59
|
export declare function formatBlockedMessage(health: ContextHealth): string;
|
|
60
|
+
/** I/O interface for audit — overridable for testing. */
|
|
61
|
+
export interface AuditIO {
|
|
62
|
+
append(path: string, data: string): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Log a --force bypass to ~/.orbit/force.log.
|
|
66
|
+
* Fire-and-forget — never blocks or throws.
|
|
67
|
+
*/
|
|
68
|
+
export declare function auditForceBypass(opts: {
|
|
69
|
+
cmd: string;
|
|
70
|
+
healthLevel: ContextHealthLevel;
|
|
71
|
+
cwd: string;
|
|
72
|
+
io?: AuditIO;
|
|
73
|
+
}): Promise<void>;
|
|
44
74
|
export interface GuardOptions {
|
|
45
75
|
cmd: string;
|
|
46
76
|
health: ContextHealth;
|
|
@@ -48,6 +78,7 @@ export interface GuardOptions {
|
|
|
48
78
|
promptConfirm?: (message: string) => Promise<boolean>;
|
|
49
79
|
force: boolean;
|
|
50
80
|
execute: () => void | Promise<void>;
|
|
81
|
+
cwd?: string;
|
|
51
82
|
}
|
|
52
83
|
/**
|
|
53
84
|
* Run a command with context guard.
|
|
@@ -56,7 +87,7 @@ export interface GuardOptions {
|
|
|
56
87
|
* | Guard needed | Force | TTY | Action |
|
|
57
88
|
* |-------------|-------|------------|---------------------|
|
|
58
89
|
* | No | * | * | Execute |
|
|
59
|
-
* | Yes | Yes | * |
|
|
90
|
+
* | Yes | Yes | * | Audit + notice + execute |
|
|
60
91
|
* | Yes | No | Yes (TTY) | Ask → execute/abort |
|
|
61
92
|
* | Yes | No | No (pipe) | BLOCK |
|
|
62
93
|
*/
|
|
@@ -8,27 +8,59 @@
|
|
|
8
8
|
* DESIGN:
|
|
9
9
|
* - Centralizzata: una sola funzione, chiamata dal router
|
|
10
10
|
* - Fail-closed: se non puoi chiedere, non eseguire
|
|
11
|
-
* -
|
|
11
|
+
* - Policy esplicita: ogni comando sensibile ha risk level e reason
|
|
12
|
+
* - Audit: --force su critical viene loggato in ~/.orbit/force.log
|
|
12
13
|
* - Override esplicito: --force bypassa la guard
|
|
13
14
|
*/
|
|
14
|
-
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { appendFile, mkdir } from 'node:fs/promises';
|
|
15
17
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
+
* Centralized policy registry for sensitive commands.
|
|
19
|
+
* Single source of truth — add new commands here.
|
|
18
20
|
*/
|
|
19
|
-
export const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
export const COMMAND_POLICIES = [
|
|
22
|
+
{
|
|
23
|
+
name: '/report',
|
|
24
|
+
aliases: ['/r'],
|
|
25
|
+
risk: 'high',
|
|
26
|
+
reason: 'Invia dati al backend Orbit',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: '/session start',
|
|
30
|
+
aliases: ['/ss'],
|
|
31
|
+
risk: 'medium',
|
|
32
|
+
reason: 'Crea sessione su sito potenzialmente sbagliato',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: '/link',
|
|
36
|
+
aliases: [],
|
|
37
|
+
risk: 'high',
|
|
38
|
+
reason: 'Modifica il collegamento progetto-sito',
|
|
39
|
+
},
|
|
25
40
|
];
|
|
41
|
+
/**
|
|
42
|
+
* Find the policy for a given command. Returns null for non-sensitive commands.
|
|
43
|
+
*/
|
|
44
|
+
export function getCommandPolicy(cmd) {
|
|
45
|
+
const lower = cmd.toLowerCase().trim();
|
|
46
|
+
for (const policy of COMMAND_POLICIES) {
|
|
47
|
+
if (lower === policy.name || lower.startsWith(policy.name + ' ')) {
|
|
48
|
+
return policy;
|
|
49
|
+
}
|
|
50
|
+
for (const alias of policy.aliases) {
|
|
51
|
+
if (lower === alias || lower.startsWith(alias + ' ')) {
|
|
52
|
+
return policy;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
26
58
|
/**
|
|
27
59
|
* Check if a command is sensitive (requires guard on critical context).
|
|
60
|
+
* Backward-compatible wrapper around getCommandPolicy.
|
|
28
61
|
*/
|
|
29
62
|
export function isSensitiveCommand(cmd) {
|
|
30
|
-
|
|
31
|
-
return SENSITIVE_COMMANDS.some(sc => lower === sc || lower.startsWith(sc + ' '));
|
|
63
|
+
return getCommandPolicy(cmd) !== null;
|
|
32
64
|
}
|
|
33
65
|
// ─── Force Flag Parsing ───────────────────────────────────────────
|
|
34
66
|
/**
|
|
@@ -36,7 +68,6 @@ export function isSensitiveCommand(cmd) {
|
|
|
36
68
|
* Returns the clean input (without --force) and whether the flag was present.
|
|
37
69
|
*/
|
|
38
70
|
export function parseForceFlag(input) {
|
|
39
|
-
// Match --force as a standalone word (not --forced, --forceful, etc.)
|
|
40
71
|
const forceRegex = /\s--force(?:\s|$)/;
|
|
41
72
|
if (forceRegex.test(` ${input} `)) {
|
|
42
73
|
const cleanInput = input.replace(/\s*--force\s*/, ' ').trim();
|
|
@@ -88,6 +119,30 @@ export function formatBlockedMessage(health) {
|
|
|
88
119
|
lines.push('');
|
|
89
120
|
return lines.join('\n');
|
|
90
121
|
}
|
|
122
|
+
// ─── Audit ────────────────────────────────────────────────────────
|
|
123
|
+
const ORBIT_DIR = join(process.env.HOME ?? '~', '.orbit');
|
|
124
|
+
const FORCE_LOG_PATH = join(ORBIT_DIR, 'force.log');
|
|
125
|
+
const defaultAuditIO = {
|
|
126
|
+
append: async (path, data) => {
|
|
127
|
+
await mkdir(ORBIT_DIR, { recursive: true });
|
|
128
|
+
await appendFile(path, data, 'utf-8');
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Log a --force bypass to ~/.orbit/force.log.
|
|
133
|
+
* Fire-and-forget — never blocks or throws.
|
|
134
|
+
*/
|
|
135
|
+
export async function auditForceBypass(opts) {
|
|
136
|
+
try {
|
|
137
|
+
const io = opts.io ?? defaultAuditIO;
|
|
138
|
+
const timestamp = new Date().toISOString();
|
|
139
|
+
const line = `${timestamp} | ${opts.cmd} | bypass ${opts.healthLevel} | ${opts.cwd}\n`;
|
|
140
|
+
await io.append(FORCE_LOG_PATH, line);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Audit failure must never block execution
|
|
144
|
+
}
|
|
145
|
+
}
|
|
91
146
|
/**
|
|
92
147
|
* Run a command with context guard.
|
|
93
148
|
*
|
|
@@ -95,19 +150,21 @@ export function formatBlockedMessage(health) {
|
|
|
95
150
|
* | Guard needed | Force | TTY | Action |
|
|
96
151
|
* |-------------|-------|------------|---------------------|
|
|
97
152
|
* | No | * | * | Execute |
|
|
98
|
-
* | Yes | Yes | * |
|
|
153
|
+
* | Yes | Yes | * | Audit + notice + execute |
|
|
99
154
|
* | Yes | No | Yes (TTY) | Ask → execute/abort |
|
|
100
155
|
* | Yes | No | No (pipe) | BLOCK |
|
|
101
156
|
*/
|
|
102
157
|
export async function runWithContextGuard(opts) {
|
|
103
|
-
const { cmd, health, output, promptConfirm, force, execute } = opts;
|
|
158
|
+
const { cmd, health, output, promptConfirm, force, execute, cwd } = opts;
|
|
104
159
|
// No guard needed → execute directly
|
|
105
160
|
if (!shouldGuard(cmd, health)) {
|
|
106
161
|
await execute();
|
|
107
162
|
return;
|
|
108
163
|
}
|
|
109
|
-
// Force → bypass
|
|
164
|
+
// Force → audit + notice + bypass
|
|
110
165
|
if (force) {
|
|
166
|
+
output(' ⚠️ Esecuzione forzata su contesto CRITICAL (--force)');
|
|
167
|
+
auditForceBypass({ cmd, healthLevel: health.level, cwd: cwd ?? process.cwd() });
|
|
111
168
|
await execute();
|
|
112
169
|
return;
|
|
113
170
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-guard.js","sourceRoot":"","sources":["../../src/lib/context-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"context-guard.js","sourceRoot":"","sources":["../../src/lib/context-guard.ts"],"names":[],"mappings":"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"}
|
package/oclif.manifest.json
CHANGED