@griffin-app/griffin-cli 1.0.29 → 1.0.30
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/README.md +12 -12
- package/dist/cli.js +25 -6
- package/dist/commands/hub/destroy.js +9 -2
- package/dist/commands/hub/integrations.js +15 -4
- package/dist/commands/hub/metrics.js +1 -1
- package/dist/commands/hub/run.js +2 -1
- package/dist/commands/hub/secrets.js +2 -6
- package/dist/core/secrets.d.ts +18 -31
- package/dist/core/secrets.js +34 -85
- package/dist/monitor-runner.js +21 -8
- package/dist/utils/output.js +6 -1
- package/dist/utils/sdk-error.js +11 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -92,18 +92,18 @@ griffin metrics --env production --period 7d --json
|
|
|
92
92
|
|
|
93
93
|
Commands are **top-level** or under a **group**. The default environment is `default` unless overridden with `--env <name>` where supported.
|
|
94
94
|
|
|
95
|
-
| Area
|
|
96
|
-
|
|
97
|
-
| **Project**
|
|
98
|
-
| **Local run**
|
|
99
|
-
| **Hub sync**
|
|
100
|
-
| **Hub runs**
|
|
101
|
-
| **Auth**
|
|
102
|
-
| **Environments**
|
|
103
|
-
| **Variables**
|
|
104
|
-
| **Secrets**
|
|
105
|
-
| **Integrations**
|
|
106
|
-
| **Notifications** | `notifications list`, `notifications test`
|
|
95
|
+
| Area | Commands | Purpose |
|
|
96
|
+
| ----------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
|
|
97
|
+
| **Project** | `init`, `validate`, `status` | Bootstrap, validate monitors, show status |
|
|
98
|
+
| **Local run** | `test` | Run monitors locally |
|
|
99
|
+
| **Hub sync** | `plan`, `apply`, `destroy` | Preview changes, push to hub, remove from hub |
|
|
100
|
+
| **Hub runs** | `runs`, `run`, `metrics` | List runs, trigger run, view metrics |
|
|
101
|
+
| **Auth** | `auth login`, `auth logout`, `auth connect`, `auth generate-key` | Cloud or self-hosted auth |
|
|
102
|
+
| **Environments** | `env list`, `env add`, `env remove` | Manage environments |
|
|
103
|
+
| **Variables** | `variables list`, `variables add`, `variables remove` | Per-environment variables (in state) |
|
|
104
|
+
| **Secrets** | `secrets list`, `secrets set`, `secrets get`, `secrets delete` | Per-environment secrets (stored on hub) |
|
|
105
|
+
| **Integrations** | `integrations list`, `integrations show`, `integrations connect`, `integrations update`, `integrations remove` | Slack, email, webhooks, etc. |
|
|
106
|
+
| **Notifications** | `notifications list`, `notifications test` | Notification rules and test sends |
|
|
107
107
|
|
|
108
108
|
### Top-level commands
|
|
109
109
|
|
package/dist/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ import { executeIntegrationsConnect } from "./commands/hub/integrations.js";
|
|
|
20
20
|
import { executeNotificationsList, executeNotificationsTest, } from "./commands/hub/notifications.js";
|
|
21
21
|
import { executeSecretsList, executeSecretsSet, executeSecretsGet, executeSecretsDelete, } from "./commands/hub/secrets.js";
|
|
22
22
|
import { executeIntegrationsList, executeIntegrationsShow, executeIntegrationsUpdate, executeIntegrationsRemove, } from "./commands/hub/integrations.js";
|
|
23
|
-
import packageInfo from
|
|
23
|
+
import packageInfo from "../package.json" with { type: "json" };
|
|
24
24
|
const program = new Command();
|
|
25
25
|
program
|
|
26
26
|
.name("griffin")
|
|
@@ -60,7 +60,11 @@ program
|
|
|
60
60
|
.option("--env <name>", "Environment name", "default")
|
|
61
61
|
.option("--json", "Output in JSON format")
|
|
62
62
|
.action(async (options) => {
|
|
63
|
-
await executePlan({
|
|
63
|
+
await executePlan({
|
|
64
|
+
...options,
|
|
65
|
+
env: options.env,
|
|
66
|
+
json: program.opts().json ?? options.json,
|
|
67
|
+
});
|
|
64
68
|
});
|
|
65
69
|
program
|
|
66
70
|
.command("apply")
|
|
@@ -70,7 +74,11 @@ program
|
|
|
70
74
|
.option("--dry-run", "Show what would be done without making changes")
|
|
71
75
|
.option("--prune", "Delete monitors on hub that don't exist locally")
|
|
72
76
|
.action(async (options) => {
|
|
73
|
-
await executeApply({
|
|
77
|
+
await executeApply({
|
|
78
|
+
...options,
|
|
79
|
+
env: options.env,
|
|
80
|
+
json: program.opts().json,
|
|
81
|
+
});
|
|
74
82
|
});
|
|
75
83
|
program
|
|
76
84
|
.command("runs")
|
|
@@ -94,7 +102,11 @@ program
|
|
|
94
102
|
.option("--wait", "Wait for run to complete")
|
|
95
103
|
.option("--force", "Run even if local monitor differs from hub")
|
|
96
104
|
.action(async (options) => {
|
|
97
|
-
await executeRun({
|
|
105
|
+
await executeRun({
|
|
106
|
+
...options,
|
|
107
|
+
env: options.env,
|
|
108
|
+
json: program.opts().json,
|
|
109
|
+
});
|
|
98
110
|
});
|
|
99
111
|
program
|
|
100
112
|
.command("metrics")
|
|
@@ -285,7 +297,10 @@ integrations
|
|
|
285
297
|
.description("Show integration details")
|
|
286
298
|
.option("--json", "Output as JSON")
|
|
287
299
|
.action(async (id, options) => {
|
|
288
|
-
await executeIntegrationsShow({
|
|
300
|
+
await executeIntegrationsShow({
|
|
301
|
+
id,
|
|
302
|
+
json: program.opts().json ?? options.json,
|
|
303
|
+
});
|
|
289
304
|
});
|
|
290
305
|
integrations
|
|
291
306
|
.command("connect [type] [provider]")
|
|
@@ -323,7 +338,11 @@ integrations
|
|
|
323
338
|
.description("Remove an integration")
|
|
324
339
|
.option("--force", "Skip confirmation")
|
|
325
340
|
.action(async (id, options) => {
|
|
326
|
-
await executeIntegrationsRemove({
|
|
341
|
+
await executeIntegrationsRemove({
|
|
342
|
+
id,
|
|
343
|
+
force: options.force,
|
|
344
|
+
json: program.opts().json,
|
|
345
|
+
});
|
|
327
346
|
});
|
|
328
347
|
// Notifications command group
|
|
329
348
|
const notifications = program
|
|
@@ -35,7 +35,11 @@ export const executeDestroy = createCommandHandler("destroy", async (options, ou
|
|
|
35
35
|
const remoteMonitors = response.data?.data;
|
|
36
36
|
fetchSpinner.succeed(`Found ${remoteMonitors.length} remote monitor(s)`);
|
|
37
37
|
if (remoteMonitors.length === 0) {
|
|
38
|
-
output.setData({
|
|
38
|
+
output.setData({
|
|
39
|
+
destroyed: [],
|
|
40
|
+
total: 0,
|
|
41
|
+
dryRun: options.dryRun ?? false,
|
|
42
|
+
});
|
|
39
43
|
output.success("No monitors to destroy.");
|
|
40
44
|
return;
|
|
41
45
|
}
|
|
@@ -67,7 +71,10 @@ export const executeDestroy = createCommandHandler("destroy", async (options, ou
|
|
|
67
71
|
if (options.dryRun) {
|
|
68
72
|
output.setData({
|
|
69
73
|
dryRun: true,
|
|
70
|
-
wouldDestroy: monitorsToDestroy.map((m) => ({
|
|
74
|
+
wouldDestroy: monitorsToDestroy.map((m) => ({
|
|
75
|
+
id: m.id,
|
|
76
|
+
name: m.name,
|
|
77
|
+
})),
|
|
71
78
|
total: monitorsToDestroy.length,
|
|
72
79
|
});
|
|
73
80
|
output.info("[DRY RUN] No changes will be made");
|
|
@@ -56,7 +56,10 @@ export const executeIntegrationsShow = createCommandHandler("integrations show",
|
|
|
56
56
|
}
|
|
57
57
|
const raw = response.data?.data;
|
|
58
58
|
if (!raw) {
|
|
59
|
-
output.setData({
|
|
59
|
+
output.setData({
|
|
60
|
+
error: "NOT_FOUND",
|
|
61
|
+
message: "Integration not found.",
|
|
62
|
+
});
|
|
60
63
|
output.error("Integration not found.");
|
|
61
64
|
output.exit(1);
|
|
62
65
|
}
|
|
@@ -120,7 +123,10 @@ export const executeIntegrationsUpdate = createCommandHandler("integrations upda
|
|
|
120
123
|
}
|
|
121
124
|
const raw = response.data?.data;
|
|
122
125
|
if (!raw) {
|
|
123
|
-
output.setData({
|
|
126
|
+
output.setData({
|
|
127
|
+
error: "NOT_FOUND",
|
|
128
|
+
message: "Integration not found.",
|
|
129
|
+
});
|
|
124
130
|
output.error("Integration not found.");
|
|
125
131
|
output.exit(1);
|
|
126
132
|
}
|
|
@@ -141,7 +147,10 @@ export const executeIntegrationsRemove = createCommandHandler("integrations remo
|
|
|
141
147
|
}
|
|
142
148
|
const raw = response.data?.data;
|
|
143
149
|
if (!raw) {
|
|
144
|
-
output.setData({
|
|
150
|
+
output.setData({
|
|
151
|
+
error: "NOT_FOUND",
|
|
152
|
+
message: "Integration not found.",
|
|
153
|
+
});
|
|
145
154
|
output.error("Integration not found.");
|
|
146
155
|
output.exit(1);
|
|
147
156
|
}
|
|
@@ -342,7 +351,9 @@ export const executeIntegrationsConnect = createCommandHandler("integrations con
|
|
|
342
351
|
}
|
|
343
352
|
}
|
|
344
353
|
else {
|
|
345
|
-
const categories = [
|
|
354
|
+
const categories = [
|
|
355
|
+
...new Set(providers.map((p) => p.category)),
|
|
356
|
+
].sort();
|
|
346
357
|
output.info("Available categories: " + categories.join(", "));
|
|
347
358
|
}
|
|
348
359
|
output.exit(1);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveEnvironment } from "../../core/state.js";
|
|
2
2
|
import { createSdkFromState } from "../../core/sdk.js";
|
|
3
3
|
import { handleSDKErrorWithOutput } from "../../utils/sdk-error.js";
|
|
4
|
-
import { createCommandHandler
|
|
4
|
+
import { createCommandHandler } from "../../utils/command-wrapper.js";
|
|
5
5
|
const METRICS_PERIODS = ["1h", "6h", "24h", "7d", "30d"];
|
|
6
6
|
/**
|
|
7
7
|
* Show metrics summary from the hub
|
package/dist/commands/hub/run.js
CHANGED
|
@@ -119,7 +119,8 @@ export const executeRun = createCommandHandler("run", async (options, output) =>
|
|
|
119
119
|
handleSDKErrorWithOutput(err, output, "Failed to fetch run status");
|
|
120
120
|
}
|
|
121
121
|
const currentRun = runStatusResponse.data?.data;
|
|
122
|
-
if (currentRun.status === "completed" ||
|
|
122
|
+
if (currentRun.status === "completed" ||
|
|
123
|
+
currentRun.status === "failed") {
|
|
123
124
|
if (currentRun.success) {
|
|
124
125
|
waitSpinner.succeed(`Run ${currentRun.status}`);
|
|
125
126
|
}
|
|
@@ -29,10 +29,10 @@ export const executeSecretsList = createCommandHandler("secrets list", async (op
|
|
|
29
29
|
output.info(`Secrets (environment: ${env})`);
|
|
30
30
|
output.blank();
|
|
31
31
|
const table = output.table({
|
|
32
|
-
head: ["Name"
|
|
32
|
+
head: ["Name"],
|
|
33
33
|
});
|
|
34
34
|
for (const s of secrets) {
|
|
35
|
-
table.push([s.name
|
|
35
|
+
table.push([s.name]);
|
|
36
36
|
}
|
|
37
37
|
output.log(table.toString());
|
|
38
38
|
});
|
|
@@ -80,8 +80,6 @@ export const executeSecretsSet = createCommandHandler("secrets set", async (opti
|
|
|
80
80
|
const result = response.data;
|
|
81
81
|
output.setData({
|
|
82
82
|
name: result.data?.name ?? options.name,
|
|
83
|
-
createdAt: result.data?.createdAt,
|
|
84
|
-
updatedAt: result.data?.updatedAt,
|
|
85
83
|
});
|
|
86
84
|
output.success(`Secret "${result.data?.name ?? options.name}" saved.`);
|
|
87
85
|
});
|
|
@@ -104,8 +102,6 @@ export const executeSecretsGet = createCommandHandler("secrets get", async (opti
|
|
|
104
102
|
const secret = response.data?.data;
|
|
105
103
|
output.setData(secret);
|
|
106
104
|
output.info(`Secret: ${secret.name}`);
|
|
107
|
-
output.dim(`Created: ${secret.createdAt ?? "-"}`);
|
|
108
|
-
output.dim(`Updated: ${secret.updatedAt ?? "-"}`);
|
|
109
105
|
});
|
|
110
106
|
/**
|
|
111
107
|
* Delete a secret (with confirmation unless --force; in JSON mode --force is required to avoid prompt).
|
package/dist/core/secrets.d.ts
CHANGED
|
@@ -1,37 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Secrets configuration for CLI
|
|
3
|
-
*
|
|
2
|
+
* Secrets configuration for CLI runs.
|
|
3
|
+
*
|
|
4
|
+
* Two providers:
|
|
5
|
+
* - `env`: reads secrets from environment variables (local dev, no hub needed)
|
|
6
|
+
* - `hub`: resolves secrets via POST /secrets/resolve on the hub API
|
|
4
7
|
*/
|
|
5
|
-
import { type SecretProvider
|
|
8
|
+
import { type SecretProvider } from "@griffin-app/griffin-executor";
|
|
9
|
+
import type { GriffinHubSdk } from "@griffin-app/griffin-hub-sdk";
|
|
6
10
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Supported configurations:
|
|
10
|
-
*
|
|
11
|
-
* 1. Environment provider (default if no config):
|
|
12
|
-
* GRIFFIN_SECRETS_PROVIDER=env
|
|
13
|
-
* GRIFFIN_SECRETS_ENV_PREFIX=APP_
|
|
14
|
-
*
|
|
15
|
-
* 2. AWS Secrets Manager:
|
|
16
|
-
* GRIFFIN_SECRETS_PROVIDER=aws
|
|
17
|
-
* GRIFFIN_SECRETS_AWS_REGION=us-east-1
|
|
18
|
-
* GRIFFIN_SECRETS_AWS_PREFIX=myapp/
|
|
19
|
-
* GRIFFIN_SECRETS_AWS_ROLE_ARN=arn:aws:iam::123:role/griffin
|
|
20
|
-
* GRIFFIN_SECRETS_AWS_EXTERNAL_ID=xyz
|
|
21
|
-
* GRIFFIN_SECRETS_AWS_ACCESS_KEY_ID=...
|
|
22
|
-
* GRIFFIN_SECRETS_AWS_SECRET_ACCESS_KEY=...
|
|
23
|
-
*
|
|
24
|
-
* 3. HashiCorp Vault:
|
|
25
|
-
* GRIFFIN_SECRETS_PROVIDER=vault
|
|
26
|
-
* GRIFFIN_SECRETS_VAULT_ADDRESS=https://vault.example.com
|
|
27
|
-
* GRIFFIN_SECRETS_VAULT_TOKEN=...
|
|
28
|
-
* GRIFFIN_SECRETS_VAULT_NAMESPACE=myapp
|
|
29
|
-
* GRIFFIN_SECRETS_VAULT_KV_VERSION=2
|
|
30
|
-
* GRIFFIN_SECRETS_VAULT_PREFIX=myapp/
|
|
11
|
+
* Create an env-based secret provider for fully-local CLI runs (no hub).
|
|
31
12
|
*/
|
|
32
|
-
export declare function
|
|
13
|
+
export declare function createEnvSecretsProvider(): SecretProvider;
|
|
33
14
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
15
|
+
* SecretProvider that resolves secrets via the hub's POST /secrets/resolve endpoint.
|
|
16
|
+
* The hub is the sole gateway for AWS Secrets Manager — no credentials leave the hub.
|
|
36
17
|
*/
|
|
37
|
-
export declare
|
|
18
|
+
export declare class HubSecretProvider implements SecretProvider {
|
|
19
|
+
readonly name = "hub";
|
|
20
|
+
private readonly sdk;
|
|
21
|
+
private readonly environment;
|
|
22
|
+
constructor(sdk: GriffinHubSdk, environment: string);
|
|
23
|
+
resolve(ref: string): Promise<string>;
|
|
24
|
+
}
|
package/dist/core/secrets.js
CHANGED
|
@@ -1,96 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Secrets configuration for CLI
|
|
3
|
-
*
|
|
2
|
+
* Secrets configuration for CLI runs.
|
|
3
|
+
*
|
|
4
|
+
* Two providers:
|
|
5
|
+
* - `env`: reads secrets from environment variables (local dev, no hub needed)
|
|
6
|
+
* - `hub`: resolves secrets via POST /secrets/resolve on the hub API
|
|
4
7
|
*/
|
|
5
|
-
import {
|
|
8
|
+
import { EnvSecretProvider, } from "@griffin-app/griffin-executor";
|
|
6
9
|
/**
|
|
7
|
-
* Environment variable
|
|
10
|
+
* Environment variable name for selecting the local secrets provider.
|
|
11
|
+
* Only "env" is supported for fully-local runs without a hub.
|
|
8
12
|
*/
|
|
9
13
|
const ENV_PREFIX = "GRIFFIN_SECRETS_";
|
|
10
14
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Supported configurations:
|
|
14
|
-
*
|
|
15
|
-
* 1. Environment provider (default if no config):
|
|
16
|
-
* GRIFFIN_SECRETS_PROVIDER=env
|
|
17
|
-
* GRIFFIN_SECRETS_ENV_PREFIX=APP_
|
|
18
|
-
*
|
|
19
|
-
* 2. AWS Secrets Manager:
|
|
20
|
-
* GRIFFIN_SECRETS_PROVIDER=aws
|
|
21
|
-
* GRIFFIN_SECRETS_AWS_REGION=us-east-1
|
|
22
|
-
* GRIFFIN_SECRETS_AWS_PREFIX=myapp/
|
|
23
|
-
* GRIFFIN_SECRETS_AWS_ROLE_ARN=arn:aws:iam::123:role/griffin
|
|
24
|
-
* GRIFFIN_SECRETS_AWS_EXTERNAL_ID=xyz
|
|
25
|
-
* GRIFFIN_SECRETS_AWS_ACCESS_KEY_ID=...
|
|
26
|
-
* GRIFFIN_SECRETS_AWS_SECRET_ACCESS_KEY=...
|
|
27
|
-
*
|
|
28
|
-
* 3. HashiCorp Vault:
|
|
29
|
-
* GRIFFIN_SECRETS_PROVIDER=vault
|
|
30
|
-
* GRIFFIN_SECRETS_VAULT_ADDRESS=https://vault.example.com
|
|
31
|
-
* GRIFFIN_SECRETS_VAULT_TOKEN=...
|
|
32
|
-
* GRIFFIN_SECRETS_VAULT_NAMESPACE=myapp
|
|
33
|
-
* GRIFFIN_SECRETS_VAULT_KV_VERSION=2
|
|
34
|
-
* GRIFFIN_SECRETS_VAULT_PREFIX=myapp/
|
|
15
|
+
* Create an env-based secret provider for fully-local CLI runs (no hub).
|
|
35
16
|
*/
|
|
36
|
-
export function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
provider: "env",
|
|
42
|
-
prefix: process.env[`${ENV_PREFIX}ENV_PREFIX`] || "",
|
|
43
|
-
env: process.env,
|
|
44
|
-
};
|
|
45
|
-
case "aws": {
|
|
46
|
-
const region = process.env[`${ENV_PREFIX}AWS_REGION`];
|
|
47
|
-
if (!region) {
|
|
48
|
-
throw new Error(`${ENV_PREFIX}AWS_REGION is required when GRIFFIN_SECRETS_PROVIDER=aws`);
|
|
49
|
-
}
|
|
50
|
-
const accessKeyId = process.env[`${ENV_PREFIX}AWS_ACCESS_KEY_ID`];
|
|
51
|
-
const secretAccessKey = process.env[`${ENV_PREFIX}AWS_SECRET_ACCESS_KEY`];
|
|
52
|
-
return {
|
|
53
|
-
provider: "aws",
|
|
54
|
-
region,
|
|
55
|
-
prefix: process.env[`${ENV_PREFIX}AWS_PREFIX`],
|
|
56
|
-
roleArn: process.env[`${ENV_PREFIX}AWS_ROLE_ARN`],
|
|
57
|
-
externalId: process.env[`${ENV_PREFIX}AWS_EXTERNAL_ID`],
|
|
58
|
-
credentials: accessKeyId && secretAccessKey
|
|
59
|
-
? { accessKeyId, secretAccessKey }
|
|
60
|
-
: undefined,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
case "vault": {
|
|
64
|
-
const address = process.env[`${ENV_PREFIX}VAULT_ADDRESS`];
|
|
65
|
-
const token = process.env[`${ENV_PREFIX}VAULT_TOKEN`];
|
|
66
|
-
if (!address) {
|
|
67
|
-
throw new Error(`${ENV_PREFIX}VAULT_ADDRESS is required when GRIFFIN_SECRETS_PROVIDER=vault`);
|
|
68
|
-
}
|
|
69
|
-
if (!token) {
|
|
70
|
-
throw new Error(`${ENV_PREFIX}VAULT_TOKEN is required when GRIFFIN_SECRETS_PROVIDER=vault`);
|
|
71
|
-
}
|
|
72
|
-
const kvVersionStr = process.env[`${ENV_PREFIX}VAULT_KV_VERSION`];
|
|
73
|
-
const kvVersion = kvVersionStr === "1" || kvVersionStr === "2"
|
|
74
|
-
? parseInt(kvVersionStr)
|
|
75
|
-
: 2;
|
|
76
|
-
return {
|
|
77
|
-
provider: "vault",
|
|
78
|
-
address,
|
|
79
|
-
token,
|
|
80
|
-
namespace: process.env[`${ENV_PREFIX}VAULT_NAMESPACE`],
|
|
81
|
-
kvVersion,
|
|
82
|
-
prefix: process.env[`${ENV_PREFIX}VAULT_PREFIX`],
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
default:
|
|
86
|
-
throw new Error(`Unknown secrets provider: ${provider}. Supported: env, aws, vault`);
|
|
87
|
-
}
|
|
17
|
+
export function createEnvSecretsProvider() {
|
|
18
|
+
return new EnvSecretProvider({
|
|
19
|
+
prefix: process.env[`${ENV_PREFIX}ENV_PREFIX`] || "",
|
|
20
|
+
env: process.env,
|
|
21
|
+
});
|
|
88
22
|
}
|
|
89
23
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
24
|
+
* SecretProvider that resolves secrets via the hub's POST /secrets/resolve endpoint.
|
|
25
|
+
* The hub is the sole gateway for AWS Secrets Manager — no credentials leave the hub.
|
|
92
26
|
*/
|
|
93
|
-
export
|
|
94
|
-
|
|
95
|
-
|
|
27
|
+
export class HubSecretProvider {
|
|
28
|
+
name = "hub";
|
|
29
|
+
sdk;
|
|
30
|
+
environment;
|
|
31
|
+
constructor(sdk, environment) {
|
|
32
|
+
this.sdk = sdk;
|
|
33
|
+
this.environment = environment;
|
|
34
|
+
}
|
|
35
|
+
async resolve(ref) {
|
|
36
|
+
const response = await this.sdk.postSecretsResolve({
|
|
37
|
+
body: { name: ref, environment: this.environment },
|
|
38
|
+
});
|
|
39
|
+
const value = response.data?.data?.value;
|
|
40
|
+
if (value === undefined) {
|
|
41
|
+
throw new Error(`Secret "${ref}" not found for environment "${this.environment}"`);
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
96
45
|
}
|
package/dist/monitor-runner.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import "tsx";
|
|
2
2
|
import { Value } from "typebox/value";
|
|
3
|
-
import { executeMonitorV1, AxiosAdapter, } from "@griffin-app/griffin-executor";
|
|
3
|
+
import { executeMonitorV1, AxiosAdapter, planHasSecrets, } from "@griffin-app/griffin-executor";
|
|
4
4
|
import { MonitorDSLSchema } from "@griffin-app/griffin-core/schema";
|
|
5
5
|
import { randomUUID } from "crypto";
|
|
6
6
|
import { loadVariables } from "./core/variables.js";
|
|
7
7
|
import { getProjectId } from "./core/state.js";
|
|
8
8
|
import { resolveMonitor } from "./resolve.js";
|
|
9
9
|
import { terminal } from "./utils/terminal.js";
|
|
10
|
-
import {
|
|
10
|
+
import { createEnvSecretsProvider, HubSecretProvider } from "./core/secrets.js";
|
|
11
|
+
import { createSdkFromState } from "./core/sdk.js";
|
|
11
12
|
function validateDsl(monitor) {
|
|
12
13
|
const errors = Value.Errors(MonitorDSLSchema, monitor);
|
|
13
14
|
if (errors.length > 0) {
|
|
@@ -25,13 +26,25 @@ export async function runTestFile(filePath, envName) {
|
|
|
25
26
|
const rawMonitor = validateDsl(defaultExport.default);
|
|
26
27
|
terminal.dim(`Project ID: ${projectId}`);
|
|
27
28
|
const resolvedMonitor = resolveMonitor(rawMonitor, projectId, envName, variables);
|
|
28
|
-
// Create secret provider
|
|
29
|
-
|
|
29
|
+
// Create secret provider: prefer hub (authenticated) for cloud secrets,
|
|
30
|
+
// fall back to env provider for fully-local runs.
|
|
31
|
+
let secretProvider;
|
|
32
|
+
const monitorV1 = { ...resolvedMonitor, id: randomUUID() };
|
|
33
|
+
if (planHasSecrets(monitorV1)) {
|
|
34
|
+
try {
|
|
35
|
+
const sdk = await createSdkFromState();
|
|
36
|
+
secretProvider = new HubSecretProvider(sdk, envName);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Hub not available — fall back to env provider
|
|
40
|
+
secretProvider = createEnvSecretsProvider();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
secretProvider = createEnvSecretsProvider();
|
|
45
|
+
}
|
|
30
46
|
try {
|
|
31
|
-
const result = await executeMonitorV1({
|
|
32
|
-
...resolvedMonitor,
|
|
33
|
-
id: randomUUID(),
|
|
34
|
-
}, "default-org", {
|
|
47
|
+
const result = await executeMonitorV1(monitorV1, "default-org", {
|
|
35
48
|
mode: "local",
|
|
36
49
|
httpClient: new AxiosAdapter(),
|
|
37
50
|
secretProvider,
|
package/dist/utils/output.js
CHANGED
|
@@ -178,7 +178,12 @@ export class OutputContext {
|
|
|
178
178
|
const envelope = {
|
|
179
179
|
ok: false,
|
|
180
180
|
command: this.commandName,
|
|
181
|
-
error: {
|
|
181
|
+
error: {
|
|
182
|
+
code,
|
|
183
|
+
message,
|
|
184
|
+
...(details !== undefined && { details }),
|
|
185
|
+
...(hint && { hint }),
|
|
186
|
+
},
|
|
182
187
|
};
|
|
183
188
|
process.stderr.write(JSON.stringify(envelope) + "\n");
|
|
184
189
|
}
|
package/dist/utils/sdk-error.js
CHANGED
|
@@ -47,7 +47,9 @@ function getSDKErrorCodeAndMessage(sdkError, context) {
|
|
|
47
47
|
return {
|
|
48
48
|
code: "CONFLICT",
|
|
49
49
|
message: `${contextMsg}Conflict`,
|
|
50
|
-
details: sdkError.body?.message
|
|
50
|
+
details: sdkError.body?.message
|
|
51
|
+
? { message: sdkError.body.message }
|
|
52
|
+
: undefined,
|
|
51
53
|
hint: "The operation conflicts with the current state.",
|
|
52
54
|
};
|
|
53
55
|
case 422:
|
|
@@ -77,7 +79,9 @@ function getSDKErrorCodeAndMessage(sdkError, context) {
|
|
|
77
79
|
details: {
|
|
78
80
|
status: sdkError.status,
|
|
79
81
|
statusText: sdkError.statusText,
|
|
80
|
-
...(sdkError.body?.message && {
|
|
82
|
+
...(sdkError.body?.message && {
|
|
83
|
+
bodyMessage: sdkError.body.message,
|
|
84
|
+
}),
|
|
81
85
|
},
|
|
82
86
|
hint: "The hub encountered an internal error.",
|
|
83
87
|
};
|
|
@@ -88,7 +92,9 @@ function getSDKErrorCodeAndMessage(sdkError, context) {
|
|
|
88
92
|
details: {
|
|
89
93
|
status: sdkError.status,
|
|
90
94
|
statusText: sdkError.statusText,
|
|
91
|
-
...(sdkError.body?.message && {
|
|
95
|
+
...(sdkError.body?.message && {
|
|
96
|
+
bodyMessage: sdkError.body.message,
|
|
97
|
+
}),
|
|
92
98
|
...(sdkError.message && { message: sdkError.message }),
|
|
93
99
|
},
|
|
94
100
|
};
|
|
@@ -116,7 +122,8 @@ export function handleSDKError(error, context) {
|
|
|
116
122
|
}
|
|
117
123
|
else if (typeof details === "object" && "errors" in details) {
|
|
118
124
|
terminal.dim("Validation failed:");
|
|
119
|
-
for (const err of details
|
|
125
|
+
for (const err of details
|
|
126
|
+
.errors) {
|
|
120
127
|
terminal.dim(` - ${err.message || err}`);
|
|
121
128
|
}
|
|
122
129
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@griffin-app/griffin-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.30",
|
|
4
4
|
"description": "CLI tool for running and managing griffin API tests",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"author": "",
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@griffin-app/griffin-hub-sdk": "1.0.
|
|
28
|
-
"@griffin-app/griffin-executor": "0.1.
|
|
27
|
+
"@griffin-app/griffin-hub-sdk": "1.0.27",
|
|
28
|
+
"@griffin-app/griffin-executor": "0.1.2",
|
|
29
29
|
"@griffin-app/griffin-core": "0.2.2",
|
|
30
30
|
"better-auth": "^1.4.17",
|
|
31
31
|
"cli-table3": "^0.6.5",
|