This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new 14a8bf414 fix(rmqctl): hash the parsed source in single-file
cataloggen (#5837)
14a8bf414 is described below
commit 14a8bf414be81f4665f43d79e68cd15ea3e38fce
Author: 0 <[email protected]>
AuthorDate: Mon Oct 12 16:15:16 2026 +0800
fix(rmqctl): hash the parsed source in single-file cataloggen (#5837)
The catalog generator's single-file mode hashed and rendered bytes it never
read.
- #5837 in `rmqctl/internal/catalog/generate/main.go`, `:315` wrote
`source, err := os.ReadFile(inputPath)` inside the `else` block, and that `:=`
declared a new block-scoped `source` shadowing the outer `var source []byte` at
`:302`, so under `-input` the outer variable stayed nil: `digest :=
sha256.Sum256(source)` at `:326` always produced `e3b0c442…` — the SHA-256 of
the empty input — and `renderSDKContract(source)` at `:340` always emitted
`null`, while the `yaml.Unmarshal(source, [...]
Tests: `TestRunSingleFileModeDigestMatchesSource` runs the generator over a
single-file input and compares the emitted `Digest` against a `crypto/sha256`
sum the test computes from the input file itself rather than from the code
under test, and asserts the rendered SDK contract is not `null`; reverting the
assignment turns both assertions red. No `tool-catalog/tools/*.yaml` change, so
nothing needs regenerating and `make catalog-verify` stays a no-op check.
---
rmqctl/internal/catalog/generate/main.go | 5 +++-
rmqctl/internal/catalog/generate/main_test.go | 37 +++++++++++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/rmqctl/internal/catalog/generate/main.go
b/rmqctl/internal/catalog/generate/main.go
index 3e209bf87..54cde5b71 100644
--- a/rmqctl/internal/catalog/generate/main.go
+++ b/rmqctl/internal/catalog/generate/main.go
@@ -312,10 +312,13 @@ func run(arguments []string) error {
return fmt.Errorf("parse merged catalog: %w", err)
}
} else {
- source, err := os.ReadFile(inputPath)
+ // Assign to the outer source instead of declaring a new
variable:
+ // the digest and the SDK contract are derived from it below.
+ fileSource, err := os.ReadFile(inputPath)
if err != nil {
return fmt.Errorf("read catalog: %w", err)
}
+ source = fileSource
if err := yaml.Unmarshal(source, &document); err != nil {
return fmt.Errorf("parse catalog: %w", err)
}
diff --git a/rmqctl/internal/catalog/generate/main_test.go
b/rmqctl/internal/catalog/generate/main_test.go
index bcf3a3f5f..b40bbb87f 100644
--- a/rmqctl/internal/catalog/generate/main_test.go
+++ b/rmqctl/internal/catalog/generate/main_test.go
@@ -17,6 +17,9 @@
package main
import (
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
"os"
"path/filepath"
"strings"
@@ -281,3 +284,37 @@ func TestRunRejectsReservedInstanceIDFlag(t *testing.T) {
t.Fatalf("err = %v, want nested instanceId rejection", err)
}
}
+
+// TestRunSingleFileModeDigestMatchesSource pins the single-file (-input) mode
+// contract: the catalog digest must be the SHA-256 of the input document, and
+// the SDK contract must be rendered from the same source. Both previously fell
+// back to the zero value of a shadowed source variable.
+func TestRunSingleFileModeDigestMatchesSource(t *testing.T) {
+ input, output := writeCatalogSource(t, platformToolSource)
+ sdk := filepath.Join(t.TempDir(), "rmq-tools.json")
+
+ if err := run([]string{"-input", input, "-output", output, "-sdk",
sdk}); err != nil {
+ t.Fatalf("generate catalog: %v", err)
+ }
+ source, err := os.ReadFile(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ digest := sha256.Sum256(source)
+ generated, err := os.ReadFile(output)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected := fmt.Sprintf("%q", hex.EncodeToString(digest[:]))
+ if !strings.Contains(string(generated), "Digest:") ||
+ !strings.Contains(string(generated), expected) {
+ t.Fatalf("generated digest does not match SHA-256 of the source
%s\n", expected)
+ }
+ contract, err := os.ReadFile(sdk)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if strings.TrimSpace(string(contract)) == "null" ||
!strings.Contains(string(contract), `"rmq.cluster.list"`) {
+ t.Fatalf("SDK contract was not rendered from the source: %s",
contract)
+ }
+}