From c54fde3ea570a1a26a9d63aadf89f804cb2e80a0 Mon Sep 17 00:00:00 2001 From: "fastedge-plugin-sync[bot]" Date: Thu, 1 Oct 2026 14:40:54 +0100 Subject: [PATCH 1/6] map @gcore-dev/fastedge-sdk-js latest version pre processing --- .github/workflows/release-plugin.yaml | 1 + scripts/sync/invoke-agent.sh | 10 +++++++++- scripts/sync/process-repos.sh | 8 +++++++- sources.json | 6 ++++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-plugin.yaml b/.github/workflows/release-plugin.yaml index f4afebd..85a96f1 100644 --- a/.github/workflows/release-plugin.yaml +++ b/.github/workflows/release-plugin.yaml @@ -39,6 +39,7 @@ on: description: "Run even if no reference changes detected" type: boolean required: false + default: false permissions: diff --git a/scripts/sync/invoke-agent.sh b/scripts/sync/invoke-agent.sh index 7197557..7a2cb23 100755 --- a/scripts/sync/invoke-agent.sh +++ b/scripts/sync/invoke-agent.sh @@ -350,7 +350,7 @@ PROMPT } _run_generator() { - local REFERENCE_FILE="" SECTION="" SOURCE_DIR="" SOURCE_FILES="" REPO_ID="" REF="" COMMIT="" OUTPUT_FILE="" INTENT_FILE="" + local REFERENCE_FILE="" SECTION="" SOURCE_DIR="" SOURCE_FILES="" REPO_ID="" REF="" COMMIT="" OUTPUT_FILE="" INTENT_FILE="" SDK_PACKAGE="" SDK_VERSION="" while [[ $# -gt 0 ]]; do case "$1" in @@ -363,6 +363,8 @@ _run_generator() { --commit) COMMIT="$2"; shift 2 ;; --output-file) OUTPUT_FILE="$2"; shift 2 ;; --intent-file) INTENT_FILE="$2"; shift 2 ;; + --sdk-package) SDK_PACKAGE="$2"; shift 2 ;; + --sdk-version) SDK_VERSION="$2"; shift 2 ;; *) echo "ERROR: Unknown argument: $1" >&2; exit 1 ;; esac done @@ -391,6 +393,12 @@ _run_generator() { local source_content source_content=$(load_source_files "$SOURCE_DIR" "$SOURCE_FILES") + # Substitute pinned SDK version with the resolved release version + if [[ -n "$SDK_PACKAGE" && -n "$SDK_VERSION" ]]; then + source_content=$(sed "s|\"${SDK_PACKAGE}\": *\"[^\"]*\"|\"${SDK_PACKAGE}\": \"^${SDK_VERSION}\"|g" <<< "$source_content") + echo "INFO: Substituted ${SDK_PACKAGE} version → ^${SDK_VERSION} in source material" >&2 + fi + local today today=$(date -u +"%Y-%m-%d") diff --git a/scripts/sync/process-repos.sh b/scripts/sync/process-repos.sh index b518a3f..de545ac 100644 --- a/scripts/sync/process-repos.sh +++ b/scripts/sync/process-repos.sh @@ -126,6 +126,8 @@ run_agents() { repo_id=$(jq -r ".repos[$idx].id" "$SOURCES_FILE") contract_path=$(jq -r ".repos[$idx].contract_path" "$SOURCES_FILE") intent_dir=$(jq -r ".repos[$idx].intent_dir" "$SOURCES_FILE") + local npm_package + npm_package=$(jq -r ".repos[$idx].npm_package // empty" "$SOURCES_FILE") local manifest_file="${checkout_dir}/${contract_path}manifest.json" @@ -214,16 +216,20 @@ run_agents() { echo "MISSING_INTENT=true" >> "$result_file" fi - local section_args=() intent_args=() source_files_args=() + local section_args=() intent_args=() source_files_args=() sdk_args=() [[ -n "$section" ]] && section_args=(--section "$section") [[ -n "$intent_file" ]] && intent_args=(--intent-file "$intent_file") [[ -n "$source_files_list" ]] && source_files_args=(--source-files "$source_files_list") + if [[ -n "$npm_package" && -n "$RESOLVED_REF" ]]; then + sdk_args=(--sdk-package "$npm_package" --sdk-version "${RESOLVED_REF#v}") + fi bash "${SCRIPT_DIR}/invoke-agent.sh" \ --role generator \ "${section_args[@]}" \ "${intent_args[@]}" \ "${source_files_args[@]}" \ + "${sdk_args[@]}" \ --reference-file "$reference_file" \ --source-dir "$checkout_dir" \ --repo-id "$repo_id" \ diff --git a/sources.json b/sources.json index c5aa49f..18f6140 100644 --- a/sources.json +++ b/sources.json @@ -19,7 +19,8 @@ "contract_path": "fastedge-plugin-source/", "intent_dir": "agent-intent-skills/fastedge-sdk-js/", "generator_agent": "claude", - "reviewer_agent": "openai" + "reviewer_agent": "openai", + "npm_package": "@gcoredev/fastedge-sdk-js" }, { "id": "fastedge-sdk-rust", @@ -39,7 +40,8 @@ "contract_path": "fastedge-plugin-source/", "intent_dir": "agent-intent-skills/proxy-wasm-sdk-as/", "generator_agent": "claude", - "reviewer_agent": "openai" + "reviewer_agent": "openai", + "npm_package": "@gcoredev/proxy-wasm-sdk-as" }, { "id": "fastedge-templates", From 34ff0e10e166fcfd02cccb2c206077a11c7f67bb Mon Sep 17 00:00:00 2001 From: "fastedge-plugin-sync[bot]" Date: Thu, 1 Oct 2026 15:50:23 +0100 Subject: [PATCH 2/6] copilot --- scripts/sync/invoke-agent.sh | 8 +++++++- scripts/sync/process-repos.sh | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/scripts/sync/invoke-agent.sh b/scripts/sync/invoke-agent.sh index 7a2cb23..a8f75bb 100755 --- a/scripts/sync/invoke-agent.sh +++ b/scripts/sync/invoke-agent.sh @@ -495,7 +495,7 @@ PROMPT } _run_reviewer() { - local INPUT_FILE="" SOURCE_DIR="" SOURCE_FILES="" OUTPUT_FILE="" + local INPUT_FILE="" SOURCE_DIR="" SOURCE_FILES="" OUTPUT_FILE="" SDK_PACKAGE="" SDK_VERSION="" while [[ $# -gt 0 ]]; do case "$1" in @@ -503,6 +503,8 @@ _run_reviewer() { --source-dir) SOURCE_DIR="$2"; shift 2 ;; --source-files) SOURCE_FILES="$2"; shift 2 ;; --output-file) OUTPUT_FILE="$2"; shift 2 ;; + --sdk-package) SDK_PACKAGE="$2"; shift 2 ;; + --sdk-version) SDK_VERSION="$2"; shift 2 ;; *) echo "ERROR: Unknown argument: $1" >&2; exit 1 ;; esac done @@ -525,6 +527,10 @@ _run_reviewer() { local source_content source_content=$(load_source_files "$SOURCE_DIR" "$SOURCE_FILES") + if [[ -n "$SDK_PACKAGE" && -n "$SDK_VERSION" ]]; then + source_content=$(sed "s|\"${SDK_PACKAGE}\": *\"[^\"]*\"|\"${SDK_PACKAGE}\": \"^${SDK_VERSION}\"|g" <<< "$source_content") + fi + local prompt prompt=$(_build_reviewer_prompt "$generated_content" "$source_content") diff --git a/scripts/sync/process-repos.sh b/scripts/sync/process-repos.sh index de545ac..371967a 100644 --- a/scripts/sync/process-repos.sh +++ b/scripts/sync/process-repos.sh @@ -126,8 +126,16 @@ run_agents() { repo_id=$(jq -r ".repos[$idx].id" "$SOURCES_FILE") contract_path=$(jq -r ".repos[$idx].contract_path" "$SOURCES_FILE") intent_dir=$(jq -r ".repos[$idx].intent_dir" "$SOURCES_FILE") - local npm_package + local npm_package sdk_version="" npm_package=$(jq -r ".repos[$idx].npm_package // empty" "$SOURCES_FILE") + if [[ -n "$npm_package" ]]; then + sdk_version=$(npm view "$npm_package" version 2>/dev/null) || sdk_version="" + if [[ -n "$sdk_version" ]]; then + echo "INFO: Resolved npm version for ${npm_package}: ${sdk_version}" >&2 + else + echo "WARN: Could not resolve npm version for ${npm_package} — skipping version substitution" >&2 + fi + fi local manifest_file="${checkout_dir}/${contract_path}manifest.json" @@ -220,8 +228,8 @@ run_agents() { [[ -n "$section" ]] && section_args=(--section "$section") [[ -n "$intent_file" ]] && intent_args=(--intent-file "$intent_file") [[ -n "$source_files_list" ]] && source_files_args=(--source-files "$source_files_list") - if [[ -n "$npm_package" && -n "$RESOLVED_REF" ]]; then - sdk_args=(--sdk-package "$npm_package" --sdk-version "${RESOLVED_REF#v}") + if [[ -n "$npm_package" && -n "$sdk_version" ]]; then + sdk_args=(--sdk-package "$npm_package" --sdk-version "$sdk_version") fi bash "${SCRIPT_DIR}/invoke-agent.sh" \ @@ -246,6 +254,7 @@ run_agents() { --input-file "$gen_output" \ --source-dir "$checkout_dir" \ "${source_files_args[@]}" \ + "${sdk_args[@]}" \ --output-file "$rev_output" < /dev/null || { echo "ERROR: Reviewer failed for '${source_key}'" >&2 echo "FAILED=1" >> "$result_file" From 3572a81af92bfced73475c05b6867c7d7d60911a Mon Sep 17 00:00:00 2001 From: "fastedge-plugin-sync[bot]" Date: Thu, 1 Oct 2026 16:42:31 +0100 Subject: [PATCH 3/6] no npm version now hard fails --- scripts/sync/process-repos.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/sync/process-repos.sh b/scripts/sync/process-repos.sh index 371967a..7b4a48f 100644 --- a/scripts/sync/process-repos.sh +++ b/scripts/sync/process-repos.sh @@ -133,7 +133,8 @@ run_agents() { if [[ -n "$sdk_version" ]]; then echo "INFO: Resolved npm version for ${npm_package}: ${sdk_version}" >&2 else - echo "WARN: Could not resolve npm version for ${npm_package} — skipping version substitution" >&2 + echo "ERROR: Could not resolve npm version for ${npm_package} — aborting to avoid advancing baseline with stale versions" >&2 + return 1 fi fi From da2524c5924b34831eb70bc32b0a36e9443602d0 Mon Sep 17 00:00:00 2001 From: "fastedge-plugin-sync[bot]" Date: Thu, 1 Oct 2026 17:03:23 +0100 Subject: [PATCH 4/6] test for new npm-package injection --- scripts/sync/tests/test-process-repos.sh | 171 +++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/scripts/sync/tests/test-process-repos.sh b/scripts/sync/tests/test-process-repos.sh index 23ebd6f..ea74ad9 100755 --- a/scripts/sync/tests/test-process-repos.sh +++ b/scripts/sync/tests/test-process-repos.sh @@ -370,6 +370,177 @@ fi # Restore stub so any future tests added below see the expected default run_agents() { OVERALL_VERDICT="ACCEPT"; CHANGED_FILES="plugins/test/ref.md"; } +# ── (8) npm_package: sdk args forwarded to both generator and reviewer ──────── +# +# Exercises run_agents directly with a real manifest + npm_package in sources.json. +# A stub npm returns a known version; a stub invoke-agent.sh records which roles +# received --sdk-package. Asserts both generator and reviewer calls carry it. + +eval "$_real_run_agents" + +_ra8_work="${TMPWORK}/run-agents-npm" +_ra8_checkout="${_ra8_work}/checkout" +_ra8_staging="${_ra8_work}/staging" +_ra8_mocks="${_ra8_work}/mocks" +_ra8_contract="fastedge-plugin-source/" +mkdir -p "${_ra8_checkout}/${_ra8_contract}" "$_ra8_staging" "$_ra8_mocks" + +cat > "${_ra8_checkout}/${_ra8_contract}manifest.json" <<'MANIFEST' +{ + "target_mapping": { + "key-a": {"reference_file": "docs/a.md"} + }, + "sources": { + "key-a": {"files": ["src/a.rs"]} + } +} +MANIFEST + +cat > "${_ra8_work}/sources.json" < "${_ra8_mocks}/invoke-agent.sh" <<'STUB' +#!/usr/bin/env bash +role="" output_file="" has_sdk=0 +while [[ $# -gt 0 ]]; do + case "$1" in + --role) role="$2"; shift 2 ;; + --output-file) output_file="$2"; shift 2 ;; + --sdk-package) has_sdk=1; shift 2 ;; + --sdk-version) shift 2 ;; + *) shift ;; + esac +done +[[ "$has_sdk" -eq 1 ]] && echo "$role" >> "${SDK_ARGS_LOG}" +[[ "$role" == "generator" ]] && echo "# Generated" > "$output_file" +[[ "$role" == "reviewer" ]] && printf 'VERDICT=ACCEPT\n\nLooks good.\n' > "$output_file" +exit 0 +STUB +chmod +x "${_ra8_mocks}/invoke-agent.sh" + +# Stub npm: returns a known version +cat > "${_ra8_mocks}/npm" <<'NPM' +#!/usr/bin/env bash +echo "3.1.4" +NPM +chmod +x "${_ra8_mocks}/npm" + +export SDK_ARGS_LOG="${_ra8_work}/sdk-args.log" +export SOURCES_FILE="${_ra8_work}/sources.json" +RESOLVED_REF="v3.1.4" +COMMIT="abc123" +SCRIPT_DIR="$_ra8_mocks" +_ra8_old_path="$PATH" +export PATH="${_ra8_mocks}:$PATH" + +run_agents 0 "$_ra8_staging" "$_ra8_checkout" 2>/dev/null +rc8=$? + +export PATH="$_ra8_old_path" +SCRIPT_DIR="$_ra_orig_script_dir" +export SOURCES_FILE="${TMPWORK}/sources.json" + +if [[ "$rc8" -eq 0 ]] \ + && grep -qF "generator" "${SDK_ARGS_LOG}" \ + && grep -qF "reviewer" "${SDK_ARGS_LOG}"; then + pass "(8) npm_package: sdk args forwarded to both generator and reviewer" +else + fail "(8) npm_package: sdk args forwarded to both generator and reviewer" \ + "exit=${rc8}, log=$(cat "${SDK_ARGS_LOG:-/dev/null}" 2>/dev/null)" +fi + +run_agents() { OVERALL_VERDICT="ACCEPT"; CHANGED_FILES="plugins/test/ref.md"; } + +# ── (9) npm lookup failure → run_agents returns 1 ──────────────────────────── +# +# Same setup as (8) but the stub npm exits 1 (simulating registry/auth failure). +# Asserts run_agents hard-fails so the baseline is never advanced with stale output. + +eval "$_real_run_agents" + +_ra9_work="${TMPWORK}/run-agents-npm-fail" +_ra9_checkout="${_ra9_work}/checkout" +_ra9_staging="${_ra9_work}/staging" +_ra9_mocks="${_ra9_work}/mocks" +_ra9_contract="fastedge-plugin-source/" +mkdir -p "${_ra9_checkout}/${_ra9_contract}" "$_ra9_staging" "$_ra9_mocks" + +cat > "${_ra9_checkout}/${_ra9_contract}manifest.json" <<'MANIFEST' +{ + "target_mapping": { + "key-a": {"reference_file": "docs/a.md"} + }, + "sources": { + "key-a": {"files": ["src/a.rs"]} + } +} +MANIFEST + +cat > "${_ra9_work}/sources.json" < "${_ra9_mocks}/npm" <<'NPM' +#!/usr/bin/env bash +exit 1 +NPM +chmod +x "${_ra9_mocks}/npm" + +export SOURCES_FILE="${_ra9_work}/sources.json" +RESOLVED_REF="v1.0.0" +COMMIT="abc123" +SCRIPT_DIR="$_ra9_mocks" +_ra9_old_path="$PATH" +export PATH="${_ra9_mocks}:$PATH" + +run_agents 0 "$_ra9_staging" "$_ra9_checkout" 2>/dev/null +rc9=$? + +export PATH="$_ra9_old_path" +SCRIPT_DIR="$_ra_orig_script_dir" +export SOURCES_FILE="${TMPWORK}/sources.json" + +if [[ "$rc9" -eq 1 ]]; then + pass "(9) npm lookup failure → run_agents returns 1" +else + fail "(9) npm lookup failure → run_agents returns 1" "exit=${rc9}" +fi + +run_agents() { OVERALL_VERDICT="ACCEPT"; CHANGED_FILES="plugins/test/ref.md"; } + # ── Summary ─────────────────────────────────────────────────────────────────── echo "" From ac3ac44f7629492244f80035595ac5e04a01268e Mon Sep 17 00:00:00 2001 From: "fastedge-plugin-sync[bot]" Date: Fri, 2 Oct 2026 09:27:52 +0100 Subject: [PATCH 5/6] test hardening --- context/sources-json-schema.md | 25 +++++++++++++++++++ .../rule7-bad-npm-package.json | 16 ++++++++++++ .../rule7-valid-npm-package.json | 16 ++++++++++++ scripts/sync/tests/test-process-repos.sh | 13 ++++++---- scripts/sync/tests/test-validate-sources.sh | 6 +++++ scripts/sync/validate-sources.sh | 9 +++++++ 6 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 scripts/sync/tests/fixtures/validate-sources/rule7-bad-npm-package.json create mode 100644 scripts/sync/tests/fixtures/validate-sources/rule7-valid-npm-package.json diff --git a/context/sources-json-schema.md b/context/sources-json-schema.md index b6d9493..5809c68 100644 --- a/context/sources-json-schema.md +++ b/context/sources-json-schema.md @@ -77,6 +77,22 @@ The pipeline: } ``` +For repos that publish an npm package, add `npm_package`: + +```json +{ + "id": "fastedge-sdk-js", + "github_url": "https://github.com/G-Core/FastEdge-sdk-js", + "ref": "latest-release", + "trigger": "schedule", + "contract_path": "fastedge-plugin-source/", + "intent_dir": "agent-intent-skills/fastedge-sdk-js/", + "generator_agent": "claude", + "reviewer_agent": "openai", + "npm_package": "@gcoredev/fastedge-sdk-js" +} +``` + | Field | Type | Required | Description | | ----------------- | ------ | -------- | ----------- | | `id` | string | yes | Unique identifier. Used in baseline tags and traceability frontmatter. Kebab-case. | @@ -87,6 +103,13 @@ The pipeline: | `intent_dir` | string | yes | Path to synthesis intent files in the plugin repo, relative to `sources.json`. Must end with `/`. Directory must exist. | | `generator_agent` | string | yes | AI agent that generates content. See **Agent Values** below. | | `reviewer_agent` | string | yes | AI agent that reviews content. **Must differ from `generator_agent`**. | +| `npm_package` | string | no | npm package name published by this repo (e.g. `@gcoredev/fastedge-sdk-js`). When present, the pipeline resolves the latest published version via `npm view version` and substitutes that version into source material before the generator and reviewer run, so generated blueprints always reference the current release. Must be a valid npm package name (scoped `@scope/name` or unscoped `name`, lowercase). Absence means no version substitution occurs. | + +### npm_package semantics + +When `npm_package` is set, `run_agents` calls `npm view version` once before the parallel entry loop. The resolved version is forwarded to both the generator and reviewer as `--sdk-version`. If the lookup fails (registry unreachable, package not found, npm unavailable), the run aborts with an error — it does **not** silently continue with stale source versions, because doing so would advance the baseline tag and suppress retries on the next scheduled run. + +**Known gap**: change detection is based on git commit SHA. A new npm publish without a corresponding git commit does not trigger regeneration. See the open issue for tracking options. ### Removed in v2 @@ -261,6 +284,7 @@ Validation runs in two places: 4. All `contract_path` values end with `/` 5. All `intent_dir` values end with `/` and the directory exists 6. No v1 fields (`updates[]`, `sparse_paths`) are present +7. `npm_package`, when present, is a valid npm package name (`@scope/name` or `name`, lowercase, no whitespace) A validation failure aborts the workflow before any sparse checkout begins. @@ -334,6 +358,7 @@ Each source repo has a `fastedge-plugin-source/CONVENTIONS.md` documenting the n - `intent_dir` must end with `/` and directory must exist (Rule 5) - `generator_agent` must differ from `reviewer_agent` (Rule 3) - No v1 fields (`updates[]`, `sparse_paths`) allowed (Rule 6) +- `npm_package`, when present, must be a valid npm package name (Rule 7) **To add webhook support** in the source repo's release workflow: diff --git a/scripts/sync/tests/fixtures/validate-sources/rule7-bad-npm-package.json b/scripts/sync/tests/fixtures/validate-sources/rule7-bad-npm-package.json new file mode 100644 index 0000000..4d5756b --- /dev/null +++ b/scripts/sync/tests/fixtures/validate-sources/rule7-bad-npm-package.json @@ -0,0 +1,16 @@ +{ + "version": "2.0", + "repos": [ + { + "id": "repo-a", + "github_url": "https://github.com/example/repo-a", + "ref": "latest-release", + "trigger": "schedule", + "contract_path": "fastedge-plugin-source/", + "intent_dir": "agent-intent-skills/fastedge-test/", + "generator_agent": "claude", + "reviewer_agent": "codex", + "npm_package": "Invalid Package Name!" + } + ] +} diff --git a/scripts/sync/tests/fixtures/validate-sources/rule7-valid-npm-package.json b/scripts/sync/tests/fixtures/validate-sources/rule7-valid-npm-package.json new file mode 100644 index 0000000..746e748 --- /dev/null +++ b/scripts/sync/tests/fixtures/validate-sources/rule7-valid-npm-package.json @@ -0,0 +1,16 @@ +{ + "version": "2.0", + "repos": [ + { + "id": "repo-a", + "github_url": "https://github.com/example/repo-a", + "ref": "latest-release", + "trigger": "schedule", + "contract_path": "fastedge-plugin-source/", + "intent_dir": "agent-intent-skills/fastedge-test/", + "generator_agent": "claude", + "reviewer_agent": "codex", + "npm_package": "@gcoredev/fastedge-sdk-js" + } + ] +} diff --git a/scripts/sync/tests/test-process-repos.sh b/scripts/sync/tests/test-process-repos.sh index ea74ad9..d0bb133 100755 --- a/scripts/sync/tests/test-process-repos.sh +++ b/scripts/sync/tests/test-process-repos.sh @@ -415,20 +415,23 @@ cat > "${_ra8_work}/sources.json" < "${_ra8_mocks}/invoke-agent.sh" <<'STUB' #!/usr/bin/env bash -role="" output_file="" has_sdk=0 +role="" output_file="" sdk_pkg="" sdk_ver="" while [[ $# -gt 0 ]]; do case "$1" in --role) role="$2"; shift 2 ;; --output-file) output_file="$2"; shift 2 ;; - --sdk-package) has_sdk=1; shift 2 ;; - --sdk-version) shift 2 ;; + --sdk-package) sdk_pkg="$2"; shift 2 ;; + --sdk-version) sdk_ver="$2"; shift 2 ;; *) shift ;; esac done -[[ "$has_sdk" -eq 1 ]] && echo "$role" >> "${SDK_ARGS_LOG}" +if [[ "$sdk_pkg" == "@gcoredev/fastedge-sdk-js" && "$sdk_ver" == "3.1.4" ]]; then + echo "$role" >> "${SDK_ARGS_LOG}" +fi [[ "$role" == "generator" ]] && echo "# Generated" > "$output_file" [[ "$role" == "reviewer" ]] && printf 'VERDICT=ACCEPT\n\nLooks good.\n' > "$output_file" exit 0 diff --git a/scripts/sync/tests/test-validate-sources.sh b/scripts/sync/tests/test-validate-sources.sh index 0d27990..fbbec2d 100755 --- a/scripts/sync/tests/test-validate-sources.sh +++ b/scripts/sync/tests/test-validate-sources.sh @@ -67,6 +67,12 @@ run "Rule 5: nonexistent intent_dir fails" \ run "Rule 6: v1 fields (updates[], sparse_paths) rejected" \ "$FIXTURES/rule6-v1-fields.json" 1 "Rule 6" +# Rule 7: npm_package format +run "Rule 7: valid scoped npm_package passes" \ + "$FIXTURES/rule7-valid-npm-package.json" 0 "validation passed" +run "Rule 7: invalid npm_package name fails" \ + "$FIXTURES/rule7-bad-npm-package.json" 1 "Rule 7" + # Missing argument label="no argument: exits with usage error" no_arg_output=$(bash "$VALIDATE" 2>&1) && no_arg_exit=0 || no_arg_exit=$? diff --git a/scripts/sync/validate-sources.sh b/scripts/sync/validate-sources.sh index 827d771..b5864f1 100755 --- a/scripts/sync/validate-sources.sh +++ b/scripts/sync/validate-sources.sh @@ -88,6 +88,15 @@ while IFS= read -r REPO_ID; do fi done < <(jq -r '.repos[].id' "$SOURCES_FILE") +# Rule 7: npm_package, when present, must be a valid npm package name +# Valid forms: @scope/name (scoped) or name (unscoped) — lowercase, no whitespace +while IFS=$'\t' read -r REPO_ID NPM_PKG; do + [[ "$NPM_PKG" == "null" || -z "$NPM_PKG" ]] && continue + if ! [[ "$NPM_PKG" =~ ^(@[a-z0-9_.-]+/)?[a-z0-9][a-z0-9_.-]*$ ]]; then + fail "Rule 7: npm_package is not a valid npm package name in repo '$REPO_ID': '$NPM_PKG' (must be @scope/name or name, lowercase)" + fi +done < <(jq -r '.repos[] | [.id, (.npm_package // "null")] | @tsv' "$SOURCES_FILE") + # Summary if [[ "$ERRORS" -gt 0 ]]; then echo "sources.json validation FAILED with $ERRORS error(s)." >&2 From 4a33ae9a978247f5ebdc0bab3c366d30e8245c21 Mon Sep 17 00:00:00 2001 From: "gordon.farquharson" <15788561+godronus@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:52:24 +0100 Subject: [PATCH 6/6] Enhance npm package validation in validate-sources.sh Updated validation logic to check npm_package type and ensure it is a string before validating the package name. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- scripts/sync/validate-sources.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/sync/validate-sources.sh b/scripts/sync/validate-sources.sh index b5864f1..5595cf0 100755 --- a/scripts/sync/validate-sources.sh +++ b/scripts/sync/validate-sources.sh @@ -90,12 +90,16 @@ done < <(jq -r '.repos[].id' "$SOURCES_FILE") # Rule 7: npm_package, when present, must be a valid npm package name # Valid forms: @scope/name (scoped) or name (unscoped) — lowercase, no whitespace -while IFS=$'\t' read -r REPO_ID NPM_PKG; do - [[ "$NPM_PKG" == "null" || -z "$NPM_PKG" ]] && continue +while IFS=$'\t' read -r REPO_ID NPM_TYPE NPM_PKG; do + [[ "$NPM_TYPE" == "null" ]] && continue + if [[ "$NPM_TYPE" != "string" ]]; then + fail "Rule 7: npm_package must be a string in repo '$REPO_ID'" + continue + fi if ! [[ "$NPM_PKG" =~ ^(@[a-z0-9_.-]+/)?[a-z0-9][a-z0-9_.-]*$ ]]; then fail "Rule 7: npm_package is not a valid npm package name in repo '$REPO_ID': '$NPM_PKG' (must be @scope/name or name, lowercase)" fi -done < <(jq -r '.repos[] | [.id, (.npm_package // "null")] | @tsv' "$SOURCES_FILE") +done < <(jq -r '.repos[] | [.id, (.npm_package | type), (.npm_package | if . == null then "" else tostring end)] | @tsv' "$SOURCES_FILE") # Summary if [[ "$ERRORS" -gt 0 ]]; then