diff --git a/go/kitup.go b/go/kitup.go index 0773406..6da2146 100644 --- a/go/kitup.go +++ b/go/kitup.go @@ -1106,10 +1106,30 @@ func readMetadata(targetDir string) (metadata, bool, bool) { if err != nil { return metadata{}, true, false } - var meta metadata - if err := json.Unmarshal(data, &meta); err != nil { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { return metadata{}, true, false } + var meta metadata + fields := map[string]any{ + "schemaVersion": &meta.SchemaVersion, + "appId": &meta.AppID, + "skillName": &meta.SkillName, + "source": &meta.Source, + "hash": &meta.Hash, + "sourceId": &meta.SourceID, + "version": &meta.Version, + "provenance": &meta.Provenance, + } + for name, destination := range fields { + value, ok := raw[name] + if !ok { + continue + } + if err := json.Unmarshal(value, destination); err != nil { + return metadata{}, true, false + } + } if !isOwnedMetadata(meta) { return metadata{}, true, false } diff --git a/testdata/cases/bundled-skill-install.json b/testdata/cases/bundled-skill-install.json index 0b5747b..e0c9dd7 100644 --- a/testdata/cases/bundled-skill-install.json +++ b/testdata/cases/bundled-skill-install.json @@ -3206,6 +3206,55 @@ ] } }, + { + "id": "uninstall-rejects-case-variant-metadata-key", + "operation": "uninstall", + "description": "Treats case-variant ownership metadata keys as unmanaged and refuses deletion.", + "options": { + "appId": "example-cli", + "skillName": "basic", + "scope": "user", + "agents": [ + "codex" + ], + "home": "$HOME", + "cwd": "$WORKSPACE" + }, + "given": { + "dirs": [ + "$HOME/.agents/skills/basic" + ], + "files": { + "$HOME/.agents/skills/basic/.kitup.json": { + "schemaVersion": 1, + "APPID": "example-cli", + "skillName": "basic", + "source": "bundled", + "hash": "sha256:abc" + }, + "$HOME/.agents/skills/basic/user-data.txt": "preserve me\n" + } + }, + "expected": { + "report": { + "removed": [], + "skipped": [], + "conflicts": [ + { + "hostId": "codex", + "skillName": "basic", + "targetDir": "$HOME/.agents/skills/basic", + "reason": "unmanaged" + } + ], + "errors": [] + }, + "filesPresent": [ + "$HOME/.agents/skills/basic/.kitup.json", + "$HOME/.agents/skills/basic/user-data.txt" + ] + } + }, { "id": "hosts-file-rejects-escaped-project-path", "operation": "install",