Files
lpm/state/repository_test.go
zeekay e72df52f3d state: decode wrapped YAML manifests; reject unwrapped
The on-disk plugin manifest format wraps every definition in a single
top-level key (`vm:` for VMs, `subnet:` for chains). The previous
yaml.Unmarshal into a bare T silently returned a zero-valued definition
when the wrapper was present (every shipped manifest), causing
`install-vm cevm-darwin-arm64` to crash on a nil URL.

Add decodeWrapped[T] that:
  - parses to yaml.Node
  - asserts a single top-level mapping containing the expected key
  - unmarshals only the value below that key into T

Unwrapped manifests are now rejected with a clear error rather than
producing a silent zero T.

Tests cover wrapped vm, wrapped chain, missing-key rejection, and
empty-input rejection. CI-PREMORTEM.md §12a in luxcpp/cevm has the
full root-cause writeup.

Also:
  - .gitignore: ignore bin/ (was leaking 15M lpm builds into git status)
  - LLM.md: directory layout reflects reality (main/main.go, not cmd/lpm/),
    document on-disk wrapper format and the chains/ vs subnets/ rename
2026-05-15 09:50:40 -07:00

76 lines
2.2 KiB
Go

// Copyright (C) 2019-2025, Lux Partners Limited. All rights reserved.
// See the file LICENSE for licensing terms.
package state
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/luxfi/lpm/types"
)
// TestDecodeWrappedVM exercises the canonical on-disk format used by every
// shipped registry entry (top-level `vm:` wrapper). Regression test for the
// silent zero-value unmarshal documented in CI-PREMORTEM.md §12a.
func TestDecodeWrappedVM(t *testing.T) {
yamlBytes := []byte(`vm:
id: "mgj786NP7uDwBCcq6YwThhaN8FLyybkCa4zBWTQbNgmK6k9A6"
alias: "cevm-darwin-arm64"
homepage: "https://github.com/luxfi/luxcpp"
description: "cevm test"
maintainers:
- "[email protected]"
installScript: "scripts/install.sh"
binaryPath: "cevm"
url: "https://example.com/cevm.tar.gz"
sha256: "0000000000000000000000000000000000000000000000000000000000000000"
version:
major: 0
minor: 1
patch: 0
`)
vm, err := decodeWrapped[types.VM](yamlBytes, vmWrapperKey)
require.NoError(t, err)
require.Equal(t, "mgj786NP7uDwBCcq6YwThhaN8FLyybkCa4zBWTQbNgmK6k9A6", vm.ID)
require.Equal(t, "cevm-darwin-arm64", vm.Alias)
require.Equal(t, "https://example.com/cevm.tar.gz", vm.URL)
require.Equal(t, "scripts/install.sh", vm.InstallScript)
require.Equal(t, "cevm", vm.BinaryPath)
require.Equal(t, "0000000000000000000000000000000000000000000000000000000000000000", vm.SHA256)
}
func TestDecodeWrappedVMMissingKey(t *testing.T) {
yamlBytes := []byte(`id: "x"
alias: "y"
url: "z"
`)
_, err := decodeWrapped[types.VM](yamlBytes, vmWrapperKey)
require.Error(t, err, "must reject unwrapped manifests instead of returning zero VM")
}
func TestDecodeWrappedChain(t *testing.T) {
yamlBytes := []byte(`subnet:
id:
mainnet: "abc"
alias: "wagmi"
homepage: "https://example.com"
description: "test"
maintainers:
- "[email protected]"
vms:
- "evm"
`)
chain, err := decodeWrapped[types.Chain](yamlBytes, chainWrapperKey)
require.NoError(t, err)
require.Equal(t, "wagmi", chain.Alias)
require.Equal(t, []string{"evm"}, chain.VMs)
require.Equal(t, "abc", chain.ID["mainnet"])
}
func TestDecodeWrappedRejectsEmpty(t *testing.T) {
_, err := decodeWrapped[types.VM]([]byte(``), vmWrapperKey)
require.Error(t, err)
}