fix(gsap-attestor): handle SPIRE's HCL v1 quoted-key format
SPIRE converts JSON plugin_data to HCL v1 native syntax with quoted
attribute names ("max_depth" = 10). HCL v2's parser rejects quoted
keys, so strip them before parsing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f4f02b0e2e
commit
68414987d5
2 changed files with 39 additions and 9 deletions
|
|
@ -367,6 +367,34 @@ func TestAttest_EndToEnd_CapabilityMask(t *testing.T) {
|
||||||
assertSelector(t, smap, "capability_mask", "0x0f")
|
assertSelector(t, smap, "capability_mask", "0x0f")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- decodeConfig tests ---
|
||||||
|
|
||||||
|
func TestDecodeConfig_SPIREFormat(t *testing.T) {
|
||||||
|
// SPIRE converts JSON plugin_data to HCL v1 native syntax with quoted keys
|
||||||
|
input := "\"max_depth\" = 10\n\n\"proc_root\" = \"/proc\""
|
||||||
|
cfg, err := decodeConfig(input)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("decodeConfig failed on SPIRE format: %v", err)
|
||||||
|
}
|
||||||
|
if cfg.MaxDepth != 10 {
|
||||||
|
t.Errorf("max_depth = %d, want 10", cfg.MaxDepth)
|
||||||
|
}
|
||||||
|
if cfg.ProcRoot != "/proc" {
|
||||||
|
t.Errorf("proc_root = %q, want /proc", cfg.ProcRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeConfig_NativeHCL(t *testing.T) {
|
||||||
|
input := "max_depth = 10\nproc_root = \"/proc\""
|
||||||
|
cfg, err := decodeConfig(input)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("decodeConfig failed on native HCL: %v", err)
|
||||||
|
}
|
||||||
|
if cfg.MaxDepth != 10 || cfg.ProcRoot != "/proc" {
|
||||||
|
t.Errorf("unexpected config: %+v", cfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- test helpers ---
|
// --- test helpers ---
|
||||||
|
|
||||||
func selectorMap(selectors []string) map[string]string {
|
func selectorMap(selectors []string) map[string]string {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/v2/hclsimple"
|
"github.com/hashicorp/hcl/v2/hclsimple"
|
||||||
|
|
@ -40,17 +40,19 @@ func (p *Plugin) Attest(ctx context.Context, req *workloadattestorv1.AttestReque
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unquoteHCLKeys strips quotes from HCL v1-style attribute names
|
||||||
|
// (e.g. `"max_depth" = 10` → `max_depth = 10`). SPIRE converts JSON
|
||||||
|
// plugin_data to HCL v1 native syntax which uses quoted keys that
|
||||||
|
// HCL v2's parser rejects.
|
||||||
|
var hclQuotedKey = regexp.MustCompile(`(?m)^(\s*)"([a-zA-Z_][a-zA-Z0-9_]*)"(\s*=)`)
|
||||||
|
|
||||||
func decodeConfig(data string) (GsapAttestorConfig, error) {
|
func decodeConfig(data string) (GsapAttestorConfig, error) {
|
||||||
var cfg GsapAttestorConfig
|
var cfg GsapAttestorConfig
|
||||||
jsonErr := hclsimple.Decode("plugin.json", []byte(data), nil, &cfg)
|
normalized := hclQuotedKey.ReplaceAllString(data, `${1}${2}${3}`)
|
||||||
if jsonErr == nil {
|
if err := hclsimple.Decode("plugin.hcl", []byte(normalized), nil, &cfg); err != nil {
|
||||||
return cfg, nil
|
return cfg, err
|
||||||
}
|
}
|
||||||
hclErr := hclsimple.Decode("plugin.hcl", []byte(data), nil, &cfg)
|
return cfg, nil
|
||||||
if hclErr == nil {
|
|
||||||
return cfg, nil
|
|
||||||
}
|
|
||||||
return cfg, fmt.Errorf("json: %v; hcl: %v; raw input: %q", jsonErr, hclErr, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) Configure(_ context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) {
|
func (p *Plugin) Configure(_ context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue