@jfrog/opencode-jfrog-plugin 0.0.2 → 0.0.4
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 +105 -51
- package/dist/index.js +30 -238
- package/package.json +6 -6
- package/skills/jfrog/SKILL.md +529 -0
- package/skills/jfrog/assets/.gitkeep +0 -0
- package/skills/jfrog/references/apptrust-entities.md +154 -0
- package/skills/jfrog/references/artifactory-api-gaps.md +206 -0
- package/skills/jfrog/references/artifactory-aql-syntax.md +656 -0
- package/skills/jfrog/references/artifactory-entities.md +236 -0
- package/skills/jfrog/references/artifactory-operations.md +178 -0
- package/skills/jfrog/references/catalog-entities.md +219 -0
- package/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md +93 -0
- package/skills/jfrog/references/general-parallel-execution.md +131 -0
- package/skills/jfrog/references/general-use-case-hints.md +27 -0
- package/skills/jfrog/references/jfrog-brand-html-report.md +98 -0
- package/skills/jfrog/references/jfrog-cli-install-upgrade.md +30 -0
- package/skills/jfrog/references/jfrog-entity-index.md +112 -0
- package/skills/jfrog/references/jfrog-login-flow.md +132 -0
- package/skills/jfrog/references/jfrog-url-references.md +51 -0
- package/skills/jfrog/references/onemodel-common-patterns.md +323 -0
- package/skills/jfrog/references/onemodel-graphql.md +446 -0
- package/skills/jfrog/references/onemodel-query-examples.md +753 -0
- package/skills/jfrog/references/platform-access-entities.md +200 -0
- package/skills/jfrog/references/platform-admin-api-gaps.md +164 -0
- package/skills/jfrog/references/platform-admin-operations.md +58 -0
- package/skills/jfrog/references/projects-api.md +241 -0
- package/skills/jfrog/references/release-lifecycle-entities.md +180 -0
- package/skills/jfrog/references/stored-packages-entities.md +165 -0
- package/skills/jfrog/references/xray-entities.md +740 -0
- package/skills/jfrog/scripts/check-environment.sh +224 -0
- package/skills/jfrog/scripts/jfrog-login-register-session.sh +84 -0
- package/skills/jfrog/scripts/jfrog-login-save-credentials.sh +128 -0
- package/skills/jfrog-package-safety-and-download/SKILL.md +275 -0
- package/sync-skills-vendor.json +5 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# check-environment.sh — Cached JFrog CLI environment check
|
|
3
|
+
#
|
|
4
|
+
# Checks if jf is installed and its version, using a 24h-TTL cache
|
|
5
|
+
# at ${JFROG_CLI_HOME_DIR:-$HOME/.jfrog}/skills-cache/jfrog-skill-state.json
|
|
6
|
+
# to avoid redundant checks. The skills-cache/ dir holds only this file and
|
|
7
|
+
# the OneModel schema cache — not temp API output.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# bash check-environment.sh [<model-slug>] [--force]
|
|
11
|
+
#
|
|
12
|
+
# stdout: bare JFROG_CLI_USER_AGENT value (one line) — agent captures it
|
|
13
|
+
# and runs `export JFROG_CLI_USER_AGENT='<v>'` once at the top of
|
|
14
|
+
# every bash invocation that calls jf
|
|
15
|
+
# stderr: JSON state (informational, also written to cache file)
|
|
16
|
+
#
|
|
17
|
+
# Exit codes:
|
|
18
|
+
# 0 — cache fresh, CLI ready
|
|
19
|
+
# 1 — cache refreshed, CLI ready
|
|
20
|
+
# 2 — jf not installed
|
|
21
|
+
# 3 — jf below MIN_CLI_VERSION (required for `jf api`)
|
|
22
|
+
|
|
23
|
+
set -euo pipefail
|
|
24
|
+
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
SKILL_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
27
|
+
JFROG_HOME="${JFROG_CLI_HOME_DIR:-$HOME/.jfrog}"
|
|
28
|
+
CACHE_DIR="$JFROG_HOME/skills-cache"
|
|
29
|
+
CACHE_FILE="$CACHE_DIR/jfrog-skill-state.json"
|
|
30
|
+
DEFAULT_TTL_HOURS=24
|
|
31
|
+
FORCE=false
|
|
32
|
+
|
|
33
|
+
# Minimum jf CLI version required by this skill. `jf api` (the generic
|
|
34
|
+
# authenticated REST pass-through used by nearly every reference in this
|
|
35
|
+
# skill) landed in 2.100.0; older CLIs fail with "unknown command: api".
|
|
36
|
+
MIN_CLI_VERSION="2.100.0"
|
|
37
|
+
|
|
38
|
+
MODEL_SLUG=""
|
|
39
|
+
for arg in "$@"; do
|
|
40
|
+
if [[ "$arg" == "--force" ]]; then
|
|
41
|
+
FORCE=true
|
|
42
|
+
elif [[ -z "$MODEL_SLUG" ]]; then
|
|
43
|
+
MODEL_SLUG="$arg"
|
|
44
|
+
fi
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
now_epoch() {
|
|
48
|
+
date -u +%s
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
iso_now() {
|
|
52
|
+
date -u '+%Y-%m-%dT%H:%M:%SZ'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Returns 0 if $1 is strictly less than $2 (semver via sort -V).
|
|
56
|
+
version_lt() {
|
|
57
|
+
[[ "$1" == "$2" ]] && return 1
|
|
58
|
+
[[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -1)" == "$1" ]]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
emit_min_version_error() {
|
|
62
|
+
local v="$1"
|
|
63
|
+
cat >&2 <<EOF
|
|
64
|
+
{"error": "jf CLI $v is below minimum $MIN_CLI_VERSION required by this skill (needed for 'jf api'). See references/jfrog-cli-install-upgrade.md."}
|
|
65
|
+
EOF
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
is_cache_fresh() {
|
|
69
|
+
if [[ ! -f "$CACHE_FILE" ]]; then
|
|
70
|
+
return 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
if ! command -v jq &>/dev/null; then
|
|
74
|
+
return 1
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
local checked_at ttl_hours checked_epoch now ttl_seconds age
|
|
78
|
+
checked_at=$(jq -r '.checked_at // empty' "$CACHE_FILE" 2>/dev/null) || return 1
|
|
79
|
+
ttl_hours=$(jq -r '.ttl_hours // 24' "$CACHE_FILE" 2>/dev/null) || return 1
|
|
80
|
+
|
|
81
|
+
if [[ -z "$checked_at" ]]; then
|
|
82
|
+
return 1
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# Parse ISO timestamp to epoch (portable: try GNU date, then BSD date)
|
|
86
|
+
if checked_epoch=$(date -d "$checked_at" +%s 2>/dev/null); then
|
|
87
|
+
: # GNU date succeeded
|
|
88
|
+
elif checked_epoch=$(date -jf '%Y-%m-%dT%H:%M:%SZ' "$checked_at" +%s 2>/dev/null); then
|
|
89
|
+
: # BSD date succeeded
|
|
90
|
+
else
|
|
91
|
+
return 1
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
now=$(now_epoch)
|
|
95
|
+
ttl_seconds=$((ttl_hours * 3600))
|
|
96
|
+
age=$((now - checked_epoch))
|
|
97
|
+
|
|
98
|
+
if (( age < ttl_seconds )); then
|
|
99
|
+
return 0
|
|
100
|
+
fi
|
|
101
|
+
return 1
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
check_cli() {
|
|
105
|
+
local cli_path cli_version
|
|
106
|
+
|
|
107
|
+
if ! cli_path=$(command -v jf 2>/dev/null); then
|
|
108
|
+
echo '{"cli_installed": false}' >&2
|
|
109
|
+
return 2
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
cli_version=$(jf --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
|
|
113
|
+
|
|
114
|
+
# Check for latest version (best-effort, non-blocking)
|
|
115
|
+
local latest_version="unknown"
|
|
116
|
+
if command -v curl &>/dev/null; then
|
|
117
|
+
latest_version=$(curl -sf --max-time 5 "https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf/" 2>/dev/null \
|
|
118
|
+
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | sort -V | tail -1 || echo "unknown")
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
local meets_minimum="true"
|
|
122
|
+
if [[ "$cli_version" == "unknown" ]] || version_lt "$cli_version" "$MIN_CLI_VERSION"; then
|
|
123
|
+
meets_minimum="false"
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
mkdir -p "$CACHE_DIR"
|
|
127
|
+
local state
|
|
128
|
+
state=$(cat <<EOF
|
|
129
|
+
{
|
|
130
|
+
"checked_at": "$(iso_now)",
|
|
131
|
+
"ttl_hours": $DEFAULT_TTL_HOURS,
|
|
132
|
+
"cli_installed": true,
|
|
133
|
+
"cli_path": "$cli_path",
|
|
134
|
+
"cli_version": "$cli_version",
|
|
135
|
+
"minimum_version": "$MIN_CLI_VERSION",
|
|
136
|
+
"meets_minimum_version": $meets_minimum,
|
|
137
|
+
"latest_version_available": "$latest_version"
|
|
138
|
+
}
|
|
139
|
+
EOF
|
|
140
|
+
)
|
|
141
|
+
echo "$state" > "$CACHE_FILE"
|
|
142
|
+
echo "$state" >&2
|
|
143
|
+
return 1
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# Detect the calling harness from environment signals. Output is one of:
|
|
147
|
+
# claude, cursor, gemini, goose, copilot, codex, unknown — or empty
|
|
148
|
+
# string when no agent signal is present (direct CLI/CI invocation).
|
|
149
|
+
# Naming matches the JFrog CLI's DetectExecutionContext() vocabulary.
|
|
150
|
+
detect_harness() {
|
|
151
|
+
if [[ -n "${CLAUDECODE:-}" || -n "${CLAUDE_CODE_ENTRYPOINT:-}" ]]; then
|
|
152
|
+
echo "claude"
|
|
153
|
+
elif [[ -n "${CURSOR_AGENT:-}" || -n "${CURSOR_CLI:-}" || -n "${CURSOR_TRACE_ID:-}" ]]; then
|
|
154
|
+
echo "cursor"
|
|
155
|
+
elif [[ -n "${GEMINI_CLI:-}" ]]; then
|
|
156
|
+
echo "gemini"
|
|
157
|
+
elif [[ -n "${GOOSE_TERMINAL:-}" ]]; then
|
|
158
|
+
echo "goose"
|
|
159
|
+
elif [[ -n "${COPILOT_CLI:-}" ]]; then
|
|
160
|
+
echo "copilot"
|
|
161
|
+
elif [[ -n "${CODEX_CI:-}" || -n "${CODEX_THREAD_ID:-}" || -n "${CODEX_SANDBOX:-}" ]]; then
|
|
162
|
+
echo "codex"
|
|
163
|
+
elif [[ -n "${AGENT:-}" || -n "$MODEL_SLUG" ]]; then
|
|
164
|
+
# Agent invoked us but we can't name it.
|
|
165
|
+
echo "unknown"
|
|
166
|
+
fi
|
|
167
|
+
# No match → print nothing; emitter omits the parens block entirely.
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
# Emit skill-level env vars to stdout (for eval by the caller)
|
|
171
|
+
emit_skill_env() {
|
|
172
|
+
local skill_version cli_version ua harness
|
|
173
|
+
# Parse version from SKILL.md YAML frontmatter (metadata.version)
|
|
174
|
+
skill_version="$(awk '/^---$/{n++; next} n==1 && /^[[:space:]]*version:/{gsub(/["'"'"']/, "", $2); print $2; exit}' "$SKILL_ROOT/SKILL.md" 2>/dev/null | tr -d '[:space:]')"
|
|
175
|
+
skill_version="${skill_version:-unknown}"
|
|
176
|
+
cli_version=$(jq -r '.cli_version // "unknown"' "$CACHE_FILE" 2>/dev/null || echo "unknown")
|
|
177
|
+
harness=$(detect_harness)
|
|
178
|
+
# Build the parens block: semicolon-separated key=value pairs.
|
|
179
|
+
local meta=""
|
|
180
|
+
if [[ -n "$harness" ]]; then
|
|
181
|
+
meta="tool=${harness}"
|
|
182
|
+
fi
|
|
183
|
+
if [[ -n "$MODEL_SLUG" ]]; then
|
|
184
|
+
if [[ -n "$meta" ]]; then
|
|
185
|
+
meta="${meta}; model=${MODEL_SLUG}"
|
|
186
|
+
else
|
|
187
|
+
meta="model=${MODEL_SLUG}"
|
|
188
|
+
fi
|
|
189
|
+
fi
|
|
190
|
+
ua="jfrog-skills/${skill_version}"
|
|
191
|
+
if [[ -n "$meta" ]]; then
|
|
192
|
+
ua="${ua} (${meta})"
|
|
193
|
+
fi
|
|
194
|
+
ua="${ua} jfrog-cli-go/${cli_version}"
|
|
195
|
+
printf '%s\n' "$ua"
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
# Main
|
|
199
|
+
if [[ "$FORCE" == "false" ]] && is_cache_fresh; then
|
|
200
|
+
cat "$CACHE_FILE" >&2
|
|
201
|
+
# Re-evaluate the minimum on every run so a bumped MIN_CLI_VERSION
|
|
202
|
+
# is enforced without waiting for the 24h cache to expire.
|
|
203
|
+
cached_version=$(jq -r '.cli_version // "unknown"' "$CACHE_FILE" 2>/dev/null)
|
|
204
|
+
if [[ "$cached_version" != "unknown" ]] && version_lt "$cached_version" "$MIN_CLI_VERSION"; then
|
|
205
|
+
emit_min_version_error "$cached_version"
|
|
206
|
+
exit 3
|
|
207
|
+
fi
|
|
208
|
+
emit_skill_env
|
|
209
|
+
exit 0
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
check_cli || exit_code=$?
|
|
213
|
+
exit_code=${exit_code:-0}
|
|
214
|
+
if (( exit_code == 2 )); then
|
|
215
|
+
exit 2
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
refreshed_version=$(jq -r '.cli_version // "unknown"' "$CACHE_FILE" 2>/dev/null)
|
|
219
|
+
if [[ "$refreshed_version" != "unknown" ]] && version_lt "$refreshed_version" "$MIN_CLI_VERSION"; then
|
|
220
|
+
emit_min_version_error "$refreshed_version"
|
|
221
|
+
exit 3
|
|
222
|
+
fi
|
|
223
|
+
emit_skill_env
|
|
224
|
+
exit 1
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# jfrog-login-register-session.sh — Verify a JFrog server and start a web login session
|
|
3
|
+
#
|
|
4
|
+
# Pings the server, generates a session UUID, and registers it with
|
|
5
|
+
# the Access API for browser-based authentication (bootstrap HTTP via
|
|
6
|
+
# `jf api --url`).
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# bash jfrog-login-register-session.sh <platform-url>
|
|
10
|
+
#
|
|
11
|
+
# Arguments:
|
|
12
|
+
# platform-url — Full JFrog Platform URL (e.g. https://mycompany.jfrog.io)
|
|
13
|
+
#
|
|
14
|
+
# Output (stdout, one key=value per line):
|
|
15
|
+
# SESSION_UUID=<uuid>
|
|
16
|
+
# VERIFY_CODE=<last 4 chars of uuid>
|
|
17
|
+
#
|
|
18
|
+
# Exit codes:
|
|
19
|
+
# 0 — Session registered successfully
|
|
20
|
+
# 1 — Missing arguments or prerequisites
|
|
21
|
+
# 2 — Server not reachable (ping failed)
|
|
22
|
+
# 3 — Session registration request failed
|
|
23
|
+
|
|
24
|
+
set -euo pipefail
|
|
25
|
+
|
|
26
|
+
jf_api_http_status() {
|
|
27
|
+
# Parses "Http Status: NNN" from jf api stderr.
|
|
28
|
+
local err_file="$1"
|
|
29
|
+
local line
|
|
30
|
+
line=$(grep -F 'Http Status:' "$err_file" 2>/dev/null | tail -1 || true)
|
|
31
|
+
if [[ "$line" =~ Http\ Status:\ ([0-9]+) ]]; then
|
|
32
|
+
echo "${BASH_REMATCH[1]}"
|
|
33
|
+
else
|
|
34
|
+
echo "0"
|
|
35
|
+
fi
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
JFROG_PLATFORM_URL="${1:-}"
|
|
39
|
+
|
|
40
|
+
if [[ -z "$JFROG_PLATFORM_URL" ]]; then
|
|
41
|
+
echo "Usage: bash $0 <platform-url>" >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
JFROG_PLATFORM_URL="${JFROG_PLATFORM_URL%/}"
|
|
46
|
+
|
|
47
|
+
if ! command -v jf &>/dev/null; then
|
|
48
|
+
echo "ERROR: jf is not installed" >&2
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
if ! command -v uuidgen &>/dev/null; then
|
|
53
|
+
echo "ERROR: uuidgen is not installed" >&2
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
TMPERR="$(mktemp)"
|
|
58
|
+
trap 'rm -f "$TMPERR"' EXIT
|
|
59
|
+
|
|
60
|
+
# Verify server is reachable (unauthenticated ping)
|
|
61
|
+
if ! jf api /artifactory/api/system/ping --url "$JFROG_PLATFORM_URL" >/dev/null 2>"$TMPERR"; then
|
|
62
|
+
PING_CODE=$(jf_api_http_status "$TMPERR")
|
|
63
|
+
echo "ERROR: Server not reachable at ${JFROG_PLATFORM_URL} (HTTP ${PING_CODE})" >&2
|
|
64
|
+
exit 2
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# Generate session UUID
|
|
68
|
+
SESSION_UUID=$(uuidgen | tr '[:upper:]' '[:lower:]')
|
|
69
|
+
VERIFY_CODE=${SESSION_UUID: -4}
|
|
70
|
+
|
|
71
|
+
# Register the session with the Access API
|
|
72
|
+
: >"$TMPERR"
|
|
73
|
+
if ! jf api /access/api/v2/authentication/jfrog_client_login/request \
|
|
74
|
+
--url "$JFROG_PLATFORM_URL" \
|
|
75
|
+
-X POST \
|
|
76
|
+
-H "Content-Type: application/json" \
|
|
77
|
+
-d "{\"session\":\"${SESSION_UUID}\"}" >/dev/null 2>"$TMPERR"; then
|
|
78
|
+
REG_CODE=$(jf_api_http_status "$TMPERR")
|
|
79
|
+
echo "ERROR: Session registration failed (HTTP ${REG_CODE})" >&2
|
|
80
|
+
exit 3
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
echo "SESSION_UUID=${SESSION_UUID}"
|
|
84
|
+
echo "VERIFY_CODE=${VERIFY_CODE}"
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# jfrog-login-save-credentials.sh — Complete web login by retrieving token and saving credentials
|
|
3
|
+
#
|
|
4
|
+
# Retrieves the one-time access token from a completed web login session,
|
|
5
|
+
# derives a server ID, saves the configuration via jf config, and verifies.
|
|
6
|
+
# Bootstrap token exchange uses `jf api --url` (before any server exists in
|
|
7
|
+
# `jf config`); verification uses `jf api` with --server-id.
|
|
8
|
+
#
|
|
9
|
+
# Leaves the current default `jf` server unchanged. Subsequent calls should
|
|
10
|
+
# pass `--server-id=<id>` explicitly (the SKILL.md "Server selection rules"
|
|
11
|
+
# require this anyway).
|
|
12
|
+
#
|
|
13
|
+
# IMPORTANT: The token endpoint is one-time-use. If this script fails after
|
|
14
|
+
# consuming the token (e.g. jf config write blocked by sandbox), the session
|
|
15
|
+
# is burned and login must restart from register-session.
|
|
16
|
+
#
|
|
17
|
+
# Usage:
|
|
18
|
+
# bash jfrog-login-save-credentials.sh <platform-url> <session-uuid>
|
|
19
|
+
#
|
|
20
|
+
# Arguments:
|
|
21
|
+
# platform-url — Full JFrog Platform URL (e.g. https://mycompany.jfrog.io)
|
|
22
|
+
# session-uuid — Session UUID from jfrog-login-register-session.sh output
|
|
23
|
+
#
|
|
24
|
+
# Output (stdout):
|
|
25
|
+
# SERVER_ID=<derived-server-id>
|
|
26
|
+
# Followed by the Artifactory version JSON on success.
|
|
27
|
+
#
|
|
28
|
+
# Exit codes:
|
|
29
|
+
# 0 — Login succeeded, credentials saved and verified
|
|
30
|
+
# 1 — Missing arguments or prerequisites
|
|
31
|
+
# 2 — Token retrieval failed (user may not have completed browser login)
|
|
32
|
+
# 3 — Empty token in response
|
|
33
|
+
# 4 — jf config save or verification failed
|
|
34
|
+
|
|
35
|
+
set -euo pipefail
|
|
36
|
+
|
|
37
|
+
jf_api_http_status() {
|
|
38
|
+
local err_file="$1"
|
|
39
|
+
local line
|
|
40
|
+
line=$(grep -F 'Http Status:' "$err_file" 2>/dev/null | tail -1 || true)
|
|
41
|
+
if [[ "$line" =~ Http\ Status:\ ([0-9]+) ]]; then
|
|
42
|
+
echo "${BASH_REMATCH[1]}"
|
|
43
|
+
else
|
|
44
|
+
echo "0"
|
|
45
|
+
fi
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
JFROG_PLATFORM_URL="${1:-}"
|
|
49
|
+
SESSION_UUID="${2:-}"
|
|
50
|
+
|
|
51
|
+
if [[ -z "$JFROG_PLATFORM_URL" || -z "$SESSION_UUID" ]]; then
|
|
52
|
+
echo "Usage: bash $0 <platform-url> <session-uuid>" >&2
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
JFROG_PLATFORM_URL="${JFROG_PLATFORM_URL%/}"
|
|
57
|
+
|
|
58
|
+
for cmd in jq jf; do
|
|
59
|
+
if ! command -v "$cmd" &>/dev/null; then
|
|
60
|
+
echo "ERROR: ${cmd} is not installed" >&2
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
done
|
|
64
|
+
|
|
65
|
+
# Derive server ID from URL
|
|
66
|
+
# SaaS: https://mycompany.jfrog.io → mycompany
|
|
67
|
+
# Self-hosted: https://artifactory.internal.corp → artifactory-internal-corp
|
|
68
|
+
JFROG_HOST=$(echo "$JFROG_PLATFORM_URL" | \
|
|
69
|
+
sed 's|^[a-z]*://||' | sed 's|\.jfrog\.io.*||' | sed 's|[./]|-|g')
|
|
70
|
+
|
|
71
|
+
# Retrieve the one-time token (stdout = JSON body; stderr = jf status lines)
|
|
72
|
+
RESP_FILE="/tmp/jf-login-resp-$$.json"
|
|
73
|
+
STDERR_FILE="/tmp/jf-login-err-$$.txt"
|
|
74
|
+
trap 'rm -f "$RESP_FILE" "$STDERR_FILE"' EXIT
|
|
75
|
+
|
|
76
|
+
: >"$STDERR_FILE"
|
|
77
|
+
set +e
|
|
78
|
+
jf api "/access/api/v2/authentication/jfrog_client_login/token/${SESSION_UUID}" \
|
|
79
|
+
--url "$JFROG_PLATFORM_URL" \
|
|
80
|
+
>"$RESP_FILE" 2>"$STDERR_FILE"
|
|
81
|
+
api_exit=$?
|
|
82
|
+
set -e
|
|
83
|
+
|
|
84
|
+
HTTP_CODE=$(jf_api_http_status "$STDERR_FILE")
|
|
85
|
+
if [[ "$HTTP_CODE" == "0" ]]; then
|
|
86
|
+
HTTP_CODE=$(jf_api_http_status "$RESP_FILE")
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
if (( api_exit != 0 )); then
|
|
90
|
+
echo "ERROR: Token retrieval failed (HTTP ${HTTP_CODE}, exit ${api_exit})." >&2
|
|
91
|
+
if [[ "$HTTP_CODE" == "400" ]]; then
|
|
92
|
+
echo "The user may not have completed the browser login yet." >&2
|
|
93
|
+
fi
|
|
94
|
+
exit 2
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
ACCESS_TOKEN=$(grep -v '\[Info\]' "$RESP_FILE" | jq -r '.access_token // empty')
|
|
98
|
+
|
|
99
|
+
if [[ -z "$ACCESS_TOKEN" ]]; then
|
|
100
|
+
echo "ERROR: Response contained no access token. Login must restart from step 1." >&2
|
|
101
|
+
exit 3
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Save credentials to jf config (writes to ~/.jfrog/, needs unrestricted filesystem)
|
|
105
|
+
jf config remove "$JFROG_HOST" --quiet 2>/dev/null || true
|
|
106
|
+
|
|
107
|
+
if ! jf config add "$JFROG_HOST" \
|
|
108
|
+
--url="$JFROG_PLATFORM_URL" \
|
|
109
|
+
--access-token="$ACCESS_TOKEN" \
|
|
110
|
+
--interactive=false 2>/dev/null; then
|
|
111
|
+
echo "ERROR: Failed to save credentials with jf config add." >&2
|
|
112
|
+
echo "This may be caused by sandbox restrictions on ~/.jfrog/ writes." >&2
|
|
113
|
+
exit 4
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
echo "SERVER_ID=${JFROG_HOST}"
|
|
117
|
+
|
|
118
|
+
echo "--- Verifying authentication ---"
|
|
119
|
+
if ! jf api "/artifactory/api/system/version" --server-id="$JFROG_HOST"; then
|
|
120
|
+
echo "ERROR: Authentication verification failed. Token may not have saved correctly." >&2
|
|
121
|
+
exit 4
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
echo
|
|
125
|
+
echo "NEXT (mandatory): ask the user whether to make '${JFROG_HOST}' the default jf server."
|
|
126
|
+
echo " - If yes: run 'jf config use ${JFROG_HOST}'"
|
|
127
|
+
echo " - If no: pass '--server-id=${JFROG_HOST}' on every subsequent jf call"
|
|
128
|
+
echo "Do not start any other JFrog operation against this server until this question is asked and answered."
|