@redpanda-data/docs-extensions-and-macros 5.23.0 โ 5.30.0
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/bin/doc-tools.js +52 -19
- package/bin/mcp-tools/versions.js +1 -1
- package/cli-utils/enterprise-sources.js +6 -6
- package/cli-utils/install-test-dependencies.sh +58 -6
- package/extensions/REFERENCE.adoc +44 -1
- package/extensions/external-link-checker.js +181 -32
- package/extensions/url-to-xref.js +5 -0
- package/extensions/util/scan-content-urls.js +78 -12
- package/extensions/version-fetcher/set-latest-version.js +18 -4
- package/mcp/CLI_INTERFACE.adoc +1 -1
- package/mcp/USER_GUIDE.adoc +4 -4
- package/package.json +1 -1
- package/tools/bundle-openapi.js +28 -10
- package/tools/get-redpanda-version.js +14 -1
- package/tools/lint-strings/diff.js +67 -1
- package/tools/lint-strings/engine.js +6 -0
- package/tools/lint-strings/index.js +32 -2
- package/tools/property-extractor/Makefile +88 -42
- package/tools/property-extractor/README.adoc +1 -1
- package/tools/property-extractor/cloud_config.py +11 -7
- package/tools/rpk-docs/rpk-docs-handler.js +98 -16
|
@@ -76,55 +76,101 @@ clean:
|
|
|
76
76
|
@echo "๐งน Cleaning upโฆ"
|
|
77
77
|
@rm -rf $(VENV) $(TMP_ROOT) $(REPO_ROOT)/autogenerated
|
|
78
78
|
|
|
79
|
-
# --- Clone or update Redpanda, checkout TAG or default branch ---
|
|
79
|
+
# --- Clone or update the Redpanda source (now in streaming-enterprise), checkout TAG or default branch ---
|
|
80
80
|
# Clones are shallow: the extractor only reads source files at a single tag,
|
|
81
81
|
# so full history is wasted time and disk.
|
|
82
|
-
# Auth
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
82
|
+
# Auth travels via a credential helper registered through GIT_CONFIG_*
|
|
83
|
+
# environment variables, never as a git -c argument (which would put the
|
|
84
|
+
# token in this process's argv, visible to anything that can list processes
|
|
85
|
+
# on the runner) and never embedded in the remote URL. The clone lives
|
|
86
|
+
# inside the installed package dir, so a persisted token would also be
|
|
87
|
+
# readable by anything that can list it -- GIT_CONFIG_* env vars don't get
|
|
88
|
+
# written to disk, so nothing persists in the clone's .git/config either.
|
|
89
|
+
# streaming-enterprise is private, so a token is required -- not just
|
|
90
|
+
# preferred the way it was when this cloned the public redpanda repo. GH_TOKEN
|
|
91
|
+
# is checked first because `doc-tools generate property-docs` pre-resolves it
|
|
92
|
+
# via cli-utils/github-token.js's full priority chain (notably GIT_CREDENTIALS,
|
|
93
|
+
# the token Antora/Netlify builds actually populate) before invoking this
|
|
94
|
+
# Makefile. REDPANDA_GITHUB_TOKEN/GITHUB_TOKEN are the fallback for invoking
|
|
95
|
+
# `make` directly, without going through doc-tools.js.
|
|
96
|
+
# An existing checkout may predate the streaming-enterprise migration and
|
|
97
|
+
# still have origin pointed at the old public redpanda repo, so the
|
|
98
|
+
# existing-directory path pins origin to REPO_URL before fetching. Pinning
|
|
99
|
+
# origin is not enough by itself: the old repo's cached remote-tracking refs
|
|
100
|
+
# and tags stay behind it, and a fetch that fails (expired token, outage,
|
|
101
|
+
# ref that does not exist) used to fall straight through to checking one of
|
|
102
|
+
# those out -- generating docs from stale public source under a tag that
|
|
103
|
+
# source never contained, with nothing in the log to say so. So a fetch has
|
|
104
|
+
# to succeed before any ref is resolved, the catch-all fetch prunes refs and
|
|
105
|
+
# tags the new origin does not have, the ref that gets checked out is the
|
|
106
|
+
# one the successful fetch actually wrote, and a TAG that is neither a tag
|
|
107
|
+
# nor a branch there is an error rather than a quiet swap to the default
|
|
108
|
+
# branch.
|
|
86
109
|
redpanda-git:
|
|
87
110
|
@mkdir -p "$(TMP_ROOT)"
|
|
88
|
-
@
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
else \
|
|
94
|
-
GH_TOKEN=$${REDPANDA_GITHUB_TOKEN:-$${GITHUB_TOKEN:-$${GH_TOKEN}}}; \
|
|
95
|
-
REPO_URL="https://github.com/redpanda-data/redpanda.git"; \
|
|
96
|
-
if [ -n "$$GH_TOKEN" ]; then \
|
|
97
|
-
echo "๐ Using authenticated clone (token provided)"; \
|
|
98
|
-
AUTH_HEADER="AUTHORIZATION: basic $$(printf '%s' "x-access-token:$$GH_TOKEN" | base64 | tr -d '\n')"; \
|
|
99
|
-
else \
|
|
100
|
-
AUTH_HEADER=""; \
|
|
101
|
-
fi; \
|
|
102
|
-
git -c http.https://github.com/.extraheader="$$AUTH_HEADER" clone -q --depth 1 --branch "$(TAG)" "$$REPO_URL" "$(REDPANDA_SRC)" 2>/dev/null || \
|
|
103
|
-
git -c http.https://github.com/.extraheader="$$AUTH_HEADER" clone -q --depth 1 "$$REPO_URL" "$(REDPANDA_SRC)"; \
|
|
111
|
+
@GH_TOKEN=$${GH_TOKEN:-$${REDPANDA_GITHUB_TOKEN:-$${GITHUB_TOKEN}}}; \
|
|
112
|
+
if [ -z "$$GH_TOKEN" ]; then \
|
|
113
|
+
echo "โ redpanda-data/streaming-enterprise is a private repository."; \
|
|
114
|
+
echo " Set GH_TOKEN, REDPANDA_GITHUB_TOKEN, or GITHUB_TOKEN to a token with access."; \
|
|
115
|
+
exit 1; \
|
|
104
116
|
fi; \
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
export GIT_MAKEFILE_CLONE_TOKEN="$$GH_TOKEN"; \
|
|
118
|
+
export GIT_CONFIG_COUNT=2; \
|
|
119
|
+
export GIT_CONFIG_KEY_0=credential.helper; \
|
|
120
|
+
export GIT_CONFIG_VALUE_0=; \
|
|
121
|
+
export GIT_CONFIG_KEY_1=credential.https://github.com.helper; \
|
|
122
|
+
export GIT_CONFIG_VALUE_1='!f() { echo "username=x-access-token"; echo "password=$$GIT_MAKEFILE_CLONE_TOKEN"; }; f'; \
|
|
123
|
+
REPO_URL="https://github.com/redpanda-data/streaming-enterprise.git"; \
|
|
124
|
+
echo "๐ Cloning/updating streaming-enterprise into $(REDPANDA_SRC)โฆ"; \
|
|
125
|
+
FETCH_LOG="$$(mktemp)"; \
|
|
126
|
+
FETCHED=""; \
|
|
127
|
+
if [ -d "$(REDPANDA_SRC)" ]; then \
|
|
128
|
+
git -C "$(REDPANDA_SRC)" remote set-url origin "$$REPO_URL" 2>/dev/null || \
|
|
129
|
+
git -C "$(REDPANDA_SRC)" remote add origin "$$REPO_URL"; \
|
|
130
|
+
if git -C "$(REDPANDA_SRC)" fetch --depth 1 -q origin "+refs/tags/$(TAG):refs/tags/$(TAG)" >>"$$FETCH_LOG" 2>&1; then \
|
|
131
|
+
FETCHED=tag; \
|
|
132
|
+
elif git -C "$(REDPANDA_SRC)" fetch --depth 1 -q origin "+refs/heads/$(TAG):refs/remotes/origin/$(TAG)" >>"$$FETCH_LOG" 2>&1; then \
|
|
133
|
+
FETCHED=branch; \
|
|
134
|
+
elif git -C "$(REDPANDA_SRC)" fetch --all --tags --prune --prune-tags -q >>"$$FETCH_LOG" 2>&1; then \
|
|
135
|
+
FETCHED=probe; \
|
|
136
|
+
fi; \
|
|
112
137
|
else \
|
|
113
|
-
|
|
114
|
-
if
|
|
115
|
-
|
|
116
|
-
git -C "$(REDPANDA_SRC)" checkout -q "$${DEFAULT_BRANCH}"; \
|
|
117
|
-
else \
|
|
118
|
-
DEFAULT_BRANCH=$$(git -C "$(REDPANDA_SRC)" ls-remote --symref origin HEAD | awk '/^ref:/ {sub(/^refs\/heads\//, "", $$2); print $$2; exit}'); \
|
|
119
|
-
if [ -z "$$DEFAULT_BRANCH" ]; then \
|
|
120
|
-
echo "โ Tag '$(TAG)' not found and the default branch could not be determined"; \
|
|
121
|
-
exit 1; \
|
|
122
|
-
fi; \
|
|
123
|
-
echo "โ ๏ธ Tag '$(TAG)' not found; falling back to '$${DEFAULT_BRANCH}'"; \
|
|
124
|
-
git -C "$(REDPANDA_SRC)" fetch --depth 1 -q origin "$$DEFAULT_BRANCH"; \
|
|
125
|
-
git -C "$(REDPANDA_SRC)" checkout -q FETCH_HEAD; \
|
|
138
|
+
echo "๐ Using authenticated clone"; \
|
|
139
|
+
if git clone -q --depth 1 --branch "$(TAG)" "$$REPO_URL" "$(REDPANDA_SRC)" >>"$$FETCH_LOG" 2>&1; then \
|
|
140
|
+
FETCHED=probe; \
|
|
126
141
|
fi; \
|
|
127
|
-
fi
|
|
142
|
+
fi; \
|
|
143
|
+
if [ -z "$$FETCHED" ]; then \
|
|
144
|
+
echo "โ Could not fetch '$(TAG)' from redpanda-data/streaming-enterprise:"; \
|
|
145
|
+
sed 's/^/ /' "$$FETCH_LOG"; \
|
|
146
|
+
echo " Not continuing: anything already in $(REDPANDA_SRC) can predate the"; \
|
|
147
|
+
echo " streaming-enterprise migration, and generating docs from it would"; \
|
|
148
|
+
echo " publish stale public source under this tag. Check that the token is"; \
|
|
149
|
+
echo " valid and has access to the repository, and that '$(TAG)' exists there."; \
|
|
150
|
+
rm -f "$$FETCH_LOG"; \
|
|
151
|
+
exit 1; \
|
|
152
|
+
fi; \
|
|
153
|
+
rm -f "$$FETCH_LOG"; \
|
|
154
|
+
case "$$FETCHED" in \
|
|
155
|
+
tag) REF="refs/tags/$(TAG)";; \
|
|
156
|
+
branch) REF="refs/remotes/origin/$(TAG)";; \
|
|
157
|
+
*) REF=""; \
|
|
158
|
+
for candidate in "refs/tags/$(TAG)" "refs/remotes/origin/$(TAG)"; do \
|
|
159
|
+
if git -C "$(REDPANDA_SRC)" rev-parse --verify -q "$$candidate" >/dev/null 2>&1; then \
|
|
160
|
+
REF="$$candidate"; \
|
|
161
|
+
break; \
|
|
162
|
+
fi; \
|
|
163
|
+
done;; \
|
|
164
|
+
esac; \
|
|
165
|
+
if [ -z "$$REF" ]; then \
|
|
166
|
+
echo "โ '$(TAG)' is neither a tag nor a branch in redpanda-data/streaming-enterprise."; \
|
|
167
|
+
echo " Not falling back to the default branch: that would publish docs labelled"; \
|
|
168
|
+
echo " '$(TAG)' built from entirely different source."; \
|
|
169
|
+
exit 1; \
|
|
170
|
+
fi; \
|
|
171
|
+
echo "๐ Checking out '$$REF'"; \
|
|
172
|
+
git -C "$(REDPANDA_SRC)" checkout -q --detach "$$REF"; \
|
|
173
|
+
git -C "$(REDPANDA_SRC)" reset --hard -q "$$REF"
|
|
128
174
|
|
|
129
175
|
# --- Clone Tree-sitter grammar & generate parser ---
|
|
130
176
|
# Skips npm install and parser generation when the generated output already
|
|
@@ -1296,7 +1296,7 @@ node generate-handlebars-docs.js test-input.json test-output
|
|
|
1296
1296
|
|
|
1297
1297
|
== Additional resources
|
|
1298
1298
|
|
|
1299
|
-
* https://github.com/redpanda-data/
|
|
1299
|
+
* https://github.com/redpanda-data/streaming-enterprise[streaming-enterprise Repository] (private; this is where the extractor clones Redpanda's source from)
|
|
1300
1300
|
* https://github.com/redpanda-data/docs-extensions-and-macros[docs-extensions-and-macros Repository]
|
|
1301
1301
|
* https://tree-sitter.github.io/tree-sitter/[Tree-sitter Documentation]
|
|
1302
1302
|
* https://handlebarsjs.com/[Handlebars.js Guide]
|
|
@@ -6,7 +6,7 @@ This module fetches cloud configuration from the cloudv2 repository to determine
|
|
|
6
6
|
which Redpanda properties are supported, editable, or readonly in cloud deployments.
|
|
7
7
|
|
|
8
8
|
Prerequisites:
|
|
9
|
-
- GITHUB_TOKEN environment variable set with appropriate permissions
|
|
9
|
+
- GH_TOKEN, GITHUB_TOKEN, or REDPANDA_GITHUB_TOKEN environment variable set with appropriate permissions
|
|
10
10
|
- Internet connection to access GitHub API
|
|
11
11
|
|
|
12
12
|
Usage:
|
|
@@ -105,14 +105,14 @@ def fetch_cloud_config(github_token: Optional[str] = None) -> CloudConfig:
|
|
|
105
105
|
"""
|
|
106
106
|
Fetch the latest cloud configuration from the redpanda-data/cloudv2 repository and return it as a CloudConfig.
|
|
107
107
|
|
|
108
|
-
This function uses a GitHub personal access token for authentication. If `github_token` is not provided, it will read GITHUB_TOKEN or REDPANDA_GITHUB_TOKEN from the environment. It downloads the most recent versioned YAML from the repository's install-pack directory, validates expected sections (`customer_managed_configs` and `readonly_cluster_config`), and constructs a CloudConfig instance.
|
|
109
|
-
|
|
108
|
+
This function uses a GitHub personal access token for authentication. If `github_token` is not provided, it will read GH_TOKEN, GITHUB_TOKEN, or REDPANDA_GITHUB_TOKEN from the environment. It downloads the most recent versioned YAML from the repository's install-pack directory, validates expected sections (`customer_managed_configs` and `readonly_cluster_config`), and constructs a CloudConfig instance.
|
|
109
|
+
|
|
110
110
|
Parameters:
|
|
111
|
-
github_token (Optional[str]): Personal access token for GitHub API. If omitted, the function will try environment variables GITHUB_TOKEN or REDPANDA_GITHUB_TOKEN.
|
|
112
|
-
|
|
111
|
+
github_token (Optional[str]): Personal access token for GitHub API. If omitted, the function will try environment variables GH_TOKEN, GITHUB_TOKEN, or REDPANDA_GITHUB_TOKEN.
|
|
112
|
+
|
|
113
113
|
Returns:
|
|
114
114
|
CloudConfig: Parsed cloud configuration for the latest available version.
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
Raises:
|
|
117
117
|
GitHubAuthError: Authentication or access problems with the GitHub API (including 401/403 responses).
|
|
118
118
|
NetworkError: Network connectivity or timeout failures when contacting the GitHub API.
|
|
@@ -120,7 +120,11 @@ def fetch_cloud_config(github_token: Optional[str] = None) -> CloudConfig:
|
|
|
120
120
|
CloudConfigError: Generic configuration error (for example, missing token) or unexpected internal failures.
|
|
121
121
|
"""
|
|
122
122
|
if not github_token:
|
|
123
|
-
|
|
123
|
+
# GH_TOKEN takes priority: `doc-tools generate property-docs` pre-resolves
|
|
124
|
+
# a token via cli-utils/github-token.js's full priority chain (GIT_CREDENTIALS,
|
|
125
|
+
# ACTIONS_BOT_TOKEN, etc.) and passes it down as GH_TOKEN, so this must see
|
|
126
|
+
# that name too -- not just the two env vars a directly-invoked `make` sets.
|
|
127
|
+
github_token = os.environ.get('GH_TOKEN') or os.environ.get('GITHUB_TOKEN') or os.environ.get('REDPANDA_GITHUB_TOKEN')
|
|
124
128
|
|
|
125
129
|
if not github_token:
|
|
126
130
|
error_msg = (
|
|
@@ -241,7 +241,31 @@ function prepareSourceFromRef(sourceRef, sourcePath = null) {
|
|
|
241
241
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rpk-source-'))
|
|
242
242
|
const repoDir = path.join(tmpDir, 'redpanda')
|
|
243
243
|
|
|
244
|
-
|
|
244
|
+
// streaming-enterprise is private, so a token is required. Auth travels
|
|
245
|
+
// via a credential helper registered through GIT_CONFIG_* environment
|
|
246
|
+
// variables, never as a git -c argument, so the token cannot appear in
|
|
247
|
+
// this process's argv (visible to anything that can list processes) and
|
|
248
|
+
// never embedded in the remote URL, so no token is persisted in the
|
|
249
|
+
// clone's .git/config either.
|
|
250
|
+
const { getGitHubToken } = require('../../cli-utils/github-token')
|
|
251
|
+
const token = getGitHubToken()
|
|
252
|
+
if (!token) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
'redpanda-data/streaming-enterprise is a private repository.\n' +
|
|
255
|
+
'Set GH_TOKEN, GITHUB_TOKEN, or REDPANDA_GITHUB_TOKEN so the clone can authenticate.'
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
const gitEnv = {
|
|
259
|
+
...process.env,
|
|
260
|
+
RPK_SOURCE_CLONE_TOKEN: token,
|
|
261
|
+
GIT_CONFIG_COUNT: '2',
|
|
262
|
+
GIT_CONFIG_KEY_0: 'credential.helper',
|
|
263
|
+
GIT_CONFIG_VALUE_0: '',
|
|
264
|
+
GIT_CONFIG_KEY_1: 'credential.https://github.com.helper',
|
|
265
|
+
GIT_CONFIG_VALUE_1: '!f() { echo "username=x-access-token"; echo "password=$RPK_SOURCE_CLONE_TOKEN"; }; f'
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
console.log(`Sparse-cloning streaming-enterprise repo (ref: ${sourceRef}) to ${repoDir}...`)
|
|
245
269
|
|
|
246
270
|
// Clone with sparse checkout
|
|
247
271
|
const cloneResult = spawnSync('git', [
|
|
@@ -250,27 +274,31 @@ function prepareSourceFromRef(sourceRef, sourcePath = null) {
|
|
|
250
274
|
'--filter=blob:none',
|
|
251
275
|
'--sparse',
|
|
252
276
|
'--branch', sourceRef,
|
|
253
|
-
'https://github.com/redpanda-data/
|
|
277
|
+
'https://github.com/redpanda-data/streaming-enterprise.git',
|
|
254
278
|
repoDir
|
|
255
279
|
], {
|
|
256
280
|
encoding: 'utf8',
|
|
257
281
|
timeout: 120000,
|
|
282
|
+
env: gitEnv,
|
|
258
283
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
259
284
|
})
|
|
260
285
|
|
|
261
286
|
if (cloneResult.status !== 0) {
|
|
262
287
|
throw new Error(
|
|
263
|
-
`Failed to clone
|
|
288
|
+
`Failed to clone streaming-enterprise repo with ref '${sourceRef}'.\n` +
|
|
264
289
|
`Make sure the branch or tag exists.\n` +
|
|
265
290
|
`Error: ${cloneResult.stderr}`
|
|
266
291
|
)
|
|
267
292
|
}
|
|
268
293
|
|
|
269
|
-
// Set sparse checkout to only get rpk
|
|
294
|
+
// Set sparse checkout to only get rpk. With --filter=blob:none, the blobs
|
|
295
|
+
// for src/go/rpk were not fetched by the clone above and are pulled lazily
|
|
296
|
+
// here, so this invocation needs the same credential helper.
|
|
270
297
|
const sparseResult = spawnSync('git', ['sparse-checkout', 'set', 'src/go/rpk'], {
|
|
271
298
|
cwd: repoDir,
|
|
272
299
|
encoding: 'utf8',
|
|
273
|
-
timeout: 60000
|
|
300
|
+
timeout: 60000,
|
|
301
|
+
env: gitEnv
|
|
274
302
|
})
|
|
275
303
|
|
|
276
304
|
if (sparseResult.status !== 0) {
|
|
@@ -292,8 +320,8 @@ function fetchRpkTreeFromSource(sourcePath) {
|
|
|
292
320
|
if (!fs.existsSync(sourcePath)) {
|
|
293
321
|
throw new Error(
|
|
294
322
|
`rpk source directory not found: ${sourcePath}\n` +
|
|
295
|
-
'To use --from-source, you need a local checkout of the
|
|
296
|
-
'Clone it with: git clone https://github.com/redpanda-data/
|
|
323
|
+
'To use --from-source, you need a local checkout of the streaming-enterprise repository (private).\n' +
|
|
324
|
+
'Clone it with: git clone https://github.com/redpanda-data/streaming-enterprise.git\n' +
|
|
297
325
|
'Then point to: <repo>/src/go/rpk'
|
|
298
326
|
)
|
|
299
327
|
}
|
|
@@ -393,8 +421,8 @@ function fetchRpkTreeFromLinuxSource(sourcePath, pluginPins = {}) {
|
|
|
393
421
|
if (!fs.existsSync(absoluteSourcePath)) {
|
|
394
422
|
throw new Error(
|
|
395
423
|
`rpk source directory not found: ${absoluteSourcePath}\n` +
|
|
396
|
-
'Expected a checkout of the
|
|
397
|
-
'Clone it with: git clone https://github.com/redpanda-data/
|
|
424
|
+
'Expected a checkout of the streaming-enterprise repository (private).\n' +
|
|
425
|
+
'Clone it with: git clone https://github.com/redpanda-data/streaming-enterprise.git'
|
|
398
426
|
)
|
|
399
427
|
}
|
|
400
428
|
|
|
@@ -1292,16 +1320,69 @@ function downloadRpkRelease(tag, destDir) {
|
|
|
1292
1320
|
return null
|
|
1293
1321
|
}
|
|
1294
1322
|
|
|
1323
|
+
// Releases now publish to streaming-enterprise (private), not the public
|
|
1324
|
+
// redpanda-data/redpanda. This function already has a fallback (the
|
|
1325
|
+
// caller builds from source instead), so a missing token warns and
|
|
1326
|
+
// returns null here rather than throwing the way the clone-only paths do.
|
|
1327
|
+
const { getGitHubToken } = require('../../cli-utils/github-token')
|
|
1328
|
+
const token = getGitHubToken()
|
|
1329
|
+
if (!token) {
|
|
1330
|
+
console.warn('No GitHub token available for the private streaming-enterprise release download; falling back to a source build.')
|
|
1331
|
+
return null
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1295
1334
|
const assetName = `rpk-${osName}-${archName}.zip`
|
|
1296
|
-
const
|
|
1335
|
+
const checksumAsset = `rpk_${tag.replace(/^v/, '')}_checksums.txt`
|
|
1297
1336
|
const zipPath = path.join(destDir, assetName)
|
|
1337
|
+
// The Authorization header reaches curl through a config file on stdin
|
|
1338
|
+
// (--config -), never as an -H argument: an argv header is readable by
|
|
1339
|
+
// any process on the host (ps, /proc) for as long as the transfer runs.
|
|
1340
|
+
const curlAuthConfig = `header = "Authorization: token ${token}"`
|
|
1341
|
+
|
|
1342
|
+
// streaming-enterprise is private, so the release's browser download URL
|
|
1343
|
+
// (releases/download/<tag>/<asset>) 404s even with a valid token: it
|
|
1344
|
+
// redirects to a signed storage URL that requires an authenticated
|
|
1345
|
+
// browser session, not a bearer token. Only the API's per-asset url
|
|
1346
|
+
// (asset.url, not asset.browser_download_url) accepts this Authorization
|
|
1347
|
+
// header, so resolve assets through the release-by-tag API first.
|
|
1348
|
+
const releaseResult = spawnSync('curl', [
|
|
1349
|
+
'-fsSL', '--retry', '5', '--retry-all-errors',
|
|
1350
|
+
'--connect-timeout', '30', '--max-time', '60',
|
|
1351
|
+
'--config', '-',
|
|
1352
|
+
'-H', 'Accept: application/vnd.github+json',
|
|
1353
|
+
`https://api.github.com/repos/redpanda-data/streaming-enterprise/releases/tags/${tag}`
|
|
1354
|
+
], { encoding: 'utf8', input: curlAuthConfig, timeout: 90000 })
|
|
1355
|
+
|
|
1356
|
+
if (releaseResult.status !== 0) {
|
|
1357
|
+
console.warn(`Could not look up release ${tag} from streaming-enterprise (draft or missing release)`)
|
|
1358
|
+
return null
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
let release
|
|
1362
|
+
try {
|
|
1363
|
+
release = JSON.parse(releaseResult.stdout)
|
|
1364
|
+
} catch {
|
|
1365
|
+
console.warn(`Could not parse release metadata for ${tag}`)
|
|
1366
|
+
return null
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
const assetUrl = (release.assets || []).find(a => a.name === assetName)?.url
|
|
1370
|
+
if (!assetUrl) {
|
|
1371
|
+
console.warn(`Release ${tag} has no asset named ${assetName} (draft or missing release asset)`)
|
|
1372
|
+
return null
|
|
1373
|
+
}
|
|
1374
|
+
const checksumUrl = (release.assets || []).find(a => a.name === checksumAsset)?.url
|
|
1298
1375
|
|
|
1299
1376
|
console.log(`Downloading ${assetName} for ${tag}...`)
|
|
1377
|
+
// Accept: application/octet-stream is required on the API asset url to
|
|
1378
|
+
// receive the binary itself instead of its JSON metadata.
|
|
1300
1379
|
const curlResult = spawnSync('curl', [
|
|
1301
1380
|
'-fL', '--retry', '5', '--retry-all-errors',
|
|
1302
1381
|
'--connect-timeout', '30', '--max-time', '300',
|
|
1303
|
-
'
|
|
1304
|
-
|
|
1382
|
+
'--config', '-',
|
|
1383
|
+
'-H', 'Accept: application/octet-stream',
|
|
1384
|
+
'-o', zipPath, assetUrl
|
|
1385
|
+
], { encoding: 'utf8', input: curlAuthConfig, timeout: 360000 })
|
|
1305
1386
|
|
|
1306
1387
|
if (curlResult.status !== 0) {
|
|
1307
1388
|
console.warn(`Could not download rpk release for ${tag} (draft or missing release asset)`)
|
|
@@ -1309,12 +1390,13 @@ function downloadRpkRelease(tag, destDir) {
|
|
|
1309
1390
|
}
|
|
1310
1391
|
|
|
1311
1392
|
// Verify against the release checksum file when it exists
|
|
1312
|
-
const checksumAsset = `rpk_${tag.replace(/^v/, '')}_checksums.txt`
|
|
1313
1393
|
const checksumPath = path.join(destDir, checksumAsset)
|
|
1314
|
-
const checksumResult = spawnSync('curl', [
|
|
1394
|
+
const checksumResult = checksumUrl ? spawnSync('curl', [
|
|
1315
1395
|
'-fsSL', '--retry', '3', '--connect-timeout', '30', '--max-time', '60',
|
|
1316
|
-
'
|
|
1317
|
-
|
|
1396
|
+
'--config', '-',
|
|
1397
|
+
'-H', 'Accept: application/octet-stream',
|
|
1398
|
+
'-o', checksumPath, checksumUrl
|
|
1399
|
+
], { encoding: 'utf8', input: curlAuthConfig, timeout: 90000 }) : { status: 1 }
|
|
1318
1400
|
|
|
1319
1401
|
if (checksumResult.status === 0) {
|
|
1320
1402
|
const expectedLine = fs.readFileSync(checksumPath, 'utf8')
|