Skip to content

Commit f631612

Browse files
MatanEden1claude
andcommitted
AX-1705 - Add JFrog CLI credential support to inject-instructions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1ffcc08 commit f631612

1 file changed

Lines changed: 49 additions & 9 deletions

File tree

plugins/jfrog/scripts/inject-instructions.mjs

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Licensed under the Apache License, Version 2.0
44
// https://www.apache.org/licenses/LICENSE-2.0
55

6+
import { execFileSync } from "node:child_process";
67
import { readFileSync } from "node:fs";
78
import path from "node:path";
89
import process from "node:process";
@@ -24,17 +25,52 @@ const forceDisabled =
2425
const forceEnabled =
2526
env("JF_AGENT_GUARD_FORCE_ENABLE") === "true";
2627

27-
async function isAgentGuardEnabledViaSettings() {
28+
// Resolve {baseUrl, token} from env vars, falling back to the JFrog CLI's
29+
// default server. Returns null when nothing resolves.
30+
function resolveCredentials() {
2831
const baseUrl = env("JFROG_URL", "JF_URL");
2932
const token = env("JFROG_ACCESS_TOKEN", "JF_ACCESS_TOKEN");
30-
if (!baseUrl) {
31-
debug("JFROG_URL/JF_URL is not set; skipping settings check");
32-
return false;
33+
if (baseUrl && token) {
34+
debug("Resolved credentials from environment variables");
35+
return { baseUrl, token };
3336
}
34-
if (!token) {
35-
debug("JFROG_ACCESS_TOKEN/JF_ACCESS_TOKEN is not set; skipping settings check");
37+
38+
// `jf config export` emits the default server as a base64-encoded JSON token.
39+
let configToken;
40+
try {
41+
configToken = execFileSync("jf", ["config", "export"], {
42+
encoding: "utf8",
43+
stdio: ["ignore", "pipe", "ignore"],
44+
}).trim();
45+
} catch (error) {
46+
debug(`'jf config export' failed (jf not on PATH or no server configured): ${error.message}`);
47+
return null;
48+
}
49+
50+
let cfg;
51+
try {
52+
cfg = JSON.parse(Buffer.from(configToken, "base64").toString("utf8"));
53+
} catch (error) {
54+
debug(`Could not decode the jf Config Token: ${error.message}`);
55+
return null;
56+
}
57+
58+
if (!cfg?.url || !cfg?.accessToken) {
59+
debug("jf Config Token did not contain a usable url + accessToken");
60+
return null;
61+
}
62+
63+
debug(`Resolved credentials via 'jf config export' (serverId: ${cfg.serverId ?? "<unknown>"})`);
64+
return { baseUrl: cfg.url, token: cfg.accessToken };
65+
}
66+
67+
async function isAgentGuardEnabledViaSettings() {
68+
const credentials = resolveCredentials();
69+
if (!credentials) {
70+
debug("No JFrog credentials resolved; skipping settings check");
3671
return false;
3772
}
73+
const { baseUrl, token } = credentials;
3874

3975
const url =
4076
baseUrl.replace(/\/+$/, "") +
@@ -92,13 +128,17 @@ try {
92128
path.join(root, "templates", "jfrog-mcp-management.md"),
93129
"utf8",
94130
);
95-
} catch {
96-
process.stdout.write("{}");
131+
} catch (error) {
132+
debug(`Could not read instructions template: ${error.message}`);
97133
process.exit(0);
98134
}
99135

136+
// The IDE consumes hookSpecificOutput.additionalContext from a SessionStart hook.
100137
process.stdout.write(
101138
JSON.stringify({
102-
additional_context: template,
139+
hookSpecificOutput: {
140+
hookEventName: "SessionStart",
141+
additionalContext: template,
142+
},
103143
}),
104144
);

0 commit comments

Comments
 (0)