From 1c21bb44db95128feba447cfbfec6a55daacad9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 16:27:35 +0000 Subject: [PATCH] chore(deps): bump github.com/gemaraproj/go-gemara from 0.0.1 to 0.0.2 Bumps [github.com/gemaraproj/go-gemara](https://github.com/gemaraproj/go-gemara) from 0.0.1 to 0.0.2. - [Release notes](https://github.com/gemaraproj/go-gemara/releases) - [Commits](https://github.com/gemaraproj/go-gemara/compare/v0.0.1...v0.0.2) --- updated-dependencies: - dependency-name: github.com/gemaraproj/go-gemara dependency-version: 0.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- .../github.com/gemaraproj/go-gemara/Makefile | 31 +- .../gemaraproj/go-gemara/actor_type.go | 72 -- .../gemaraproj/go-gemara/checklist.go | 2 +- .../gemaraproj/go-gemara/confidence_level.go | 42 - .../github.com/gemaraproj/go-gemara/enums.go | 732 ++++++++++++++++++ .../go-gemara/gemaraconv/catalog.go | 2 +- .../go-gemara/gemaraconv/guidance.go | 16 +- .../go-gemara/gemaraconv/test-data.go | 16 +- .../gemaraproj/go-gemara/generated_types.go | 700 +++++++++++------ .../gemaraproj/go-gemara/loaders.go | 2 +- .../github.com/gemaraproj/go-gemara/result.go | 67 -- vendor/modules.txt | 4 +- 14 files changed, 1234 insertions(+), 458 deletions(-) delete mode 100644 vendor/github.com/gemaraproj/go-gemara/actor_type.go delete mode 100644 vendor/github.com/gemaraproj/go-gemara/confidence_level.go create mode 100644 vendor/github.com/gemaraproj/go-gemara/enums.go delete mode 100644 vendor/github.com/gemaraproj/go-gemara/result.go diff --git a/go.mod b/go.mod index aa968108..71901a39 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/charmbracelet/log v0.4.2 github.com/charmbracelet/x/term v0.2.2 github.com/defenseunicorns/go-oscal v0.7.0 - github.com/gemaraproj/go-gemara v0.0.1 + github.com/gemaraproj/go-gemara v0.0.2 github.com/goccy/go-yaml v1.19.2 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-plugin v1.7.0 diff --git a/go.sum b/go.sum index 11a8b77c..959c2f73 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,8 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/gemaraproj/go-gemara v0.0.1 h1:5LVVN6gchiOvC2T6j2nohso16U2uTIcPg1jhD4TDWQQ= -github.com/gemaraproj/go-gemara v0.0.1/go.mod h1:diPp9MxIzNT8pyk4lP4odg5UeSoGCkSUoIy0JnBzCcU= +github.com/gemaraproj/go-gemara v0.0.2 h1:XA8HFQK5B6ltU5Xc0Z3eMArATiVuXjfbHR65lDmdTHQ= +github.com/gemaraproj/go-gemara v0.0.2/go.mod h1:hm4ELSJ9W/L413seDnlFIbHrXbNq6+YJK7DFQHHjNk4= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= diff --git a/vendor/github.com/gemaraproj/go-gemara/Makefile b/vendor/github.com/gemaraproj/go-gemara/Makefile index 24f895d9..2e50e7e3 100644 --- a/vendor/github.com/gemaraproj/go-gemara/Makefile +++ b/vendor/github.com/gemaraproj/go-gemara/Makefile @@ -10,7 +10,7 @@ GOFLAGS := COVERFILE := coverage.out TESTCOVERAGE_THRESHOLD := 71 GOLANGCI_LINT := golangci-lint -SPECVERSION := v0.19.1 +SPECVERSION := v0.20.0 .PHONY: all tidy fmtcheck fmt vet lint test testcov race coverage-check build install generate ci-local clean help @@ -66,11 +66,11 @@ test: @echo " > Running go test (monorepo-aware; will skip if module not present)" @sh -c '\ if [ -d "$(REPO_ROOT)/go-gemara" ]; then \ - cd $(REPO_ROOT)/go-gemara && go list ./... >/dev/null 2>&1 && go test $(GOFLAGS) ./... || echo "Skipping tests: no module in go-gemara"; \ + cd $(REPO_ROOT)/go-gemara && if go list ./... >/dev/null 2>&1; then go test $(GOFLAGS) ./...; else echo "Skipping tests: no module in go-gemara"; fi; \ elif [ -f "$(REPO_ROOT)/go.mod" ]; then \ - cd $(REPO_ROOT) && go list ./... >/dev/null 2>&1 && go test $(GOFLAGS) ./... || echo "Skipping tests: module not available"; \ + cd $(REPO_ROOT) && if go list ./... >/dev/null 2>&1; then go test $(GOFLAGS) ./...; else echo "Skipping tests: module not available"; fi; \ else \ - cd $(REPO_ROOT) && go list ./go-gemara/... >/dev/null 2>&1 && go test $(GOFLAGS) ./go-gemara/... || echo "Skipping tests: package not available"; \ + cd $(REPO_ROOT) && if go list ./go-gemara/... >/dev/null 2>&1; then go test $(GOFLAGS) ./go-gemara/...; else echo "Skipping tests: package not available"; fi; \ fi' @@ -81,11 +81,11 @@ testcov: @echo " > Running tests with coverage (monorepo-aware; will skip if module not present)" @sh -c '\ if [ -d "$(REPO_ROOT)/go-gemara" ]; then \ - cd $(REPO_ROOT)/go-gemara && go list ./... >/dev/null 2>&1 && go test $(GOFLAGS) ./... -coverprofile=$(abspath $(COVERFILE)) -covermode=count || echo "Skipping testcov: no module in go-gemara"; \ + cd $(REPO_ROOT)/go-gemara && if go list ./... >/dev/null 2>&1; then go test $(GOFLAGS) ./... -coverprofile=$(abspath $(COVERFILE)) -covermode=count; else echo "Skipping testcov: no module in go-gemara"; fi; \ elif [ -f "$(REPO_ROOT)/go.mod" ]; then \ - cd $(REPO_ROOT) && go list ./... >/dev/null 2>&1 && go test $(GOFLAGS) ./... -coverprofile=$(abspath $(COVERFILE)) -covermode=count || echo "Skipping testcov: module not available"; \ + cd $(REPO_ROOT) && if go list ./... >/dev/null 2>&1; then go test $(GOFLAGS) ./... -coverprofile=$(abspath $(COVERFILE)) -covermode=count; else echo "Skipping testcov: module not available"; fi; \ else \ - cd $(REPO_ROOT) && go list ./go-gemara/... >/dev/null 2>&1 && go test $(GOFLAGS) ./go-gemara/... -coverprofile=$(abspath $(COVERFILE)) -covermode=count || echo "Skipping testcov: package not available"; \ + cd $(REPO_ROOT) && if go list ./go-gemara/... >/dev/null 2>&1; then go test $(GOFLAGS) ./go-gemara/... -coverprofile=$(abspath $(COVERFILE)) -covermode=count; else echo "Skipping testcov: package not available"; fi; \ fi' @echo " > Coverage summary:" @sh -c 'if [ -f "$(abspath $(COVERFILE))" ]; then go tool cover -func=$(abspath $(COVERFILE)) | grep total || true; else echo "No coverage file generated"; fi' @@ -96,11 +96,11 @@ race: @echo " > Running tests with race detector (monorepo-aware; will skip if module not present)" @sh -c '\ if [ -d "$(REPO_ROOT)/go-gemara" ]; then \ - cd $(REPO_ROOT)/go-gemara && go list ./... >/dev/null 2>&1 && go test -race ./... || echo "Skipping race: no module in go-gemara"; \ + cd $(REPO_ROOT)/go-gemara && if go list ./... >/dev/null 2>&1; then go test -race ./...; else echo "Skipping race: no module in go-gemara"; fi; \ elif [ -f "$(REPO_ROOT)/go.mod" ]; then \ - cd $(REPO_ROOT) && go list ./... >/dev/null 2>&1 && go test -race ./... || echo "Skipping race: module not available"; \ + cd $(REPO_ROOT) && if go list ./... >/dev/null 2>&1; then go test -race ./...; else echo "Skipping race: module not available"; fi; \ else \ - cd $(REPO_ROOT) && go list ./go-gemara/... >/dev/null 2>&1 && go test -race ./go-gemara/... || echo "Skipping race: package not available"; \ + cd $(REPO_ROOT) && if go list ./go-gemara/... >/dev/null 2>&1; then go test -race ./go-gemara/...; else echo "Skipping race: package not available"; fi; \ fi' @@ -137,18 +137,25 @@ install: # Generate files from CUE schemas # Generates Go types from the Gemara CUE package with stable and experimental variants -generate: +old-nonfunctional-generate: @echo " > Generating types from Gemara CUE package" @cue def github.com/gemaraproj/gemara@$(SPECVERSION) --outfile schema.cue # Required after using CUE Def to find the properly defined control types - @sed -i 's/let control_9 = control/let control_9 = #ControlEvaluation.control/' schema.cue + # If running from darwin OS, add '' after -i + sed -i 's/let control_9 = control/let control_9 = #ControlEvaluation.control/' schema.cue @cue exp gengotypes schema.cue @mv cue_types_gen.go generated_types.go @go run ./cmd/typestagger generated_types.go @rm schema.cue +genlocal: + @echo " > Generating types from 'gemara' package" + @cue exp gengotypes ../gemara:gemara + @mv ../gemara/cue_types_gemara_gen.go generated_types.go + @go run ./cmd/typestagger generated_types.go + @rm schema.cue # Runs the small subset used by CI for a quick local check ci-local: fmtcheck vet lint testcov coverage-check diff --git a/vendor/github.com/gemaraproj/go-gemara/actor_type.go b/vendor/github.com/gemaraproj/go-gemara/actor_type.go deleted file mode 100644 index 31812bbc..00000000 --- a/vendor/github.com/gemaraproj/go-gemara/actor_type.go +++ /dev/null @@ -1,72 +0,0 @@ -package gemara - -import ( - "encoding/json" - "fmt" - - "github.com/gemaraproj/go-gemara/internal/loaders" -) - -// ActorType specifies type of actor interacting in the workflow (human/software) -type ActorType int - -const ( - // Software indicates the actor creates outputs without human intervention. - Software ActorType = iota - // Human indicates the actor creates outputs as a result of human review or judgment. - Human - // SoftwareAssisted indicates the actor creates outputs with software assistance but requires human oversight or judgment. - SoftwareAssisted -) - -var evaluatorTypeToString = map[ActorType]string{ - Software: "Software", - Human: "Human", - SoftwareAssisted: "Software-Assisted", -} - -var stringToEvaluatorType = map[string]ActorType{ - "Software": Software, - "Human": Human, - "Software-Assisted": SoftwareAssisted, -} - -func (e *ActorType) String() string { - return evaluatorTypeToString[*e] -} - -// MarshalYAML ensures that ActorType is serialized as a string in YAML -func (e *ActorType) MarshalYAML() (interface{}, error) { - return e.String(), nil -} - -// UnmarshalYAML ensures that ActorType can be deserialized from a YAML string -func (e *ActorType) UnmarshalYAML(data []byte) error { - var s string - if err := loaders.UnmarshalYAML(data, &s); err != nil { - return err - } - if val, ok := stringToEvaluatorType[s]; ok { - *e = val - return nil - } - return fmt.Errorf("invalid ActorType: %s", s) -} - -// MarshalJSON ensures that ActorType is serialized as a string in JSON -func (e *ActorType) MarshalJSON() ([]byte, error) { - return json.Marshal(e.String()) -} - -// UnmarshalJSON ensures that ActorType can be deserialized from a JSON string -func (e *ActorType) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - if val, ok := stringToEvaluatorType[s]; ok { - *e = val - return nil - } - return fmt.Errorf("invalid ActorType: %s", s) -} diff --git a/vendor/github.com/gemaraproj/go-gemara/checklist.go b/vendor/github.com/gemaraproj/go-gemara/checklist.go index d0ccfdee..0b2622a2 100644 --- a/vendor/github.com/gemaraproj/go-gemara/checklist.go +++ b/vendor/github.com/gemaraproj/go-gemara/checklist.go @@ -141,7 +141,7 @@ func buildChecklistItems(plan *AssessmentPlan) ([]ChecklistItem, error) { item := ChecklistItem{ PlanId: plan.Id, MethodDescription: method.Description, - MethodType: method.Type, + MethodType: method.Type.String(), Frequency: plan.Frequency, EvidenceRequirements: plan.EvidenceRequirements, } diff --git a/vendor/github.com/gemaraproj/go-gemara/confidence_level.go b/vendor/github.com/gemaraproj/go-gemara/confidence_level.go deleted file mode 100644 index 1a544860..00000000 --- a/vendor/github.com/gemaraproj/go-gemara/confidence_level.go +++ /dev/null @@ -1,42 +0,0 @@ -package gemara - -import "encoding/json" - -// ConfidenceLevel indicates the evaluator's confidence level in an assessment result. -// This is designed to restrict the possible confidence level values to a set of known levels. -type ConfidenceLevel int - -const ( - // NotSet indicates the confidence level has not been set yet (initial/default state). - NotSet ConfidenceLevel = iota - // Undetermined indicates the confidence level could not be determined (sticky, like Unknown result). - Undetermined - // Low indicates the evaluator has low confidence in this result. - Low - // Medium indicates the evaluator has moderate confidence in this result. - Medium - // High indicates the evaluator has high confidence in this result. - High -) - -var confidenceLevelToString = map[ConfidenceLevel]string{ - NotSet: "Not Set", - Undetermined: "Undetermined", - Low: "Low", - Medium: "Medium", - High: "High", -} - -func (c ConfidenceLevel) String() string { - return confidenceLevelToString[c] -} - -// MarshalYAML ensures that ConfidenceLevel is serialized as a string in YAML -func (c ConfidenceLevel) MarshalYAML() (interface{}, error) { - return c.String(), nil -} - -// MarshalJSON ensures that ConfidenceLevel is serialized as a string in JSON -func (c ConfidenceLevel) MarshalJSON() ([]byte, error) { - return json.Marshal(c.String()) -} diff --git a/vendor/github.com/gemaraproj/go-gemara/enums.go b/vendor/github.com/gemaraproj/go-gemara/enums.go new file mode 100644 index 00000000..6f66c7a7 --- /dev/null +++ b/vendor/github.com/gemaraproj/go-gemara/enums.go @@ -0,0 +1,732 @@ +package gemara + +import ( + "encoding/json" + "fmt" + "sort" + "strings" + + "github.com/gemaraproj/go-gemara/internal/loaders" +) + +// Result represents the result of a control evaluation +type Result int + +// ArtifactType identifies the kind of Gemara artifact for unambiguous parsing +type ArtifactType int + +// EntityType specifies the type of entity (human or tool) interacting in the workflow. +type EntityType int + +// Lifecycle represents the lifecycle state of a guideline, control, or assessment requirement +type Lifecycle int + +// EntryType enumerates the atomic units within Gemara artifacts that can participate in mappings +type EntryType int + +// ConfidenceLevel indicates the evaluator's confidence level in an assessment result. +type ConfidenceLevel int + +// RelationshipType enumerates the nature of the mapping between entries. +type RelationshipType int + +// MethodType enumerates the category of evaluation or enforcement method. +type MethodType int + +// Severity defines the allowed impact levels for a risk. +type Severity int + +// GuidanceType restricts the possible types that a catalog may be listed as. +type GuidanceType int + +// RiskAppetite defines the acceptable level of exposure for a risk category. +type RiskAppetite int + +// ModType defines the type of modification to the assessment requirement. +type ModType int + +const ( + NotRun Result = iota + Passed + Failed + NeedsReview + NotApplicable + Unknown +) + +const ( + ControlCatalogArtifact ArtifactType = iota + EvaluationLogArtifact + GuidanceCatalogArtifact + MappingDocumentArtifact + PolicyArtifact + ThreatCatalogArtifact + VectorCatalogArtifact +) + +const ( + Human EntityType = iota + Software + SoftwareAssisted +) + +const ( + LifecycleActive Lifecycle = iota + LifecycleDraft + LifecycleDeprecated + LifecycleRetired +) + +const ( + EntryTypeGuideline EntryType = iota + EntryTypeStatement + EntryTypeControl + EntryTypeAssessmentRequirement + EntryTypeVector +) + +const ( + Undetermined ConfidenceLevel = iota + Low + Medium + High +) + +const ( + RelImplements RelationshipType = iota + RelImplementedBy + RelSupports + RelSupportedBy + RelEquivalent + RelSubsumes + RelNoMatch + RelRelatesTo +) + +const ( + MethodManual MethodType = iota + MethodBehavioral + MethodAutomated + MethodAutoremediation + MethodGate +) + +const ( + SeverityLow Severity = iota + SeverityMedium + SeverityHigh + SeverityCritical +) + +const ( + GuidanceStandard GuidanceType = iota + GuidanceRegulation + GuidanceBestPractice + GuidanceFramework +) + +const ( + RiskAppetiteZero RiskAppetite = iota + RiskAppetiteLow + RiskAppetiteModerate + RiskAppetiteHigh +) + +const ( + ModAdd ModType = iota + ModModify + ModRemove + ModReplace + ModOverride +) + +var ( + toString = map[Result]string{ + NotRun: "Not Run", + Passed: "Passed", + Failed: "Failed", + NeedsReview: "Needs Review", + NotApplicable: "Not Applicable", + Unknown: "Unknown", + } + + stringToResult = map[string]Result{ + "Not Run": NotRun, + "Passed": Passed, + "Failed": Failed, + "Needs Review": NeedsReview, + "Not Applicable": NotApplicable, + "Unknown": Unknown, + } + + lifecycleToString = map[Lifecycle]string{ + LifecycleActive: "Active", + LifecycleDraft: "Draft", + LifecycleDeprecated: "Deprecated", + LifecycleRetired: "Retired", + } + + stringToLifecycle = map[string]Lifecycle{ + "Active": LifecycleActive, + "Draft": LifecycleDraft, + "Deprecated": LifecycleDeprecated, + "Retired": LifecycleRetired, + } + + artifactTypeToString = map[ArtifactType]string{ + ControlCatalogArtifact: "ControlCatalog", + EvaluationLogArtifact: "EvaluationLog", + GuidanceCatalogArtifact: "GuidanceCatalog", + MappingDocumentArtifact: "MappingDocument", + PolicyArtifact: "Policy", + ThreatCatalogArtifact: "ThreatCatalog", + VectorCatalogArtifact: "VectorCatalog", + } + + stringToArtifactType = map[string]ArtifactType{ + "ControlCatalog": ControlCatalogArtifact, + "EvaluationLog": EvaluationLogArtifact, + "GuidanceCatalog": GuidanceCatalogArtifact, + "MappingDocument": MappingDocumentArtifact, + "Policy": PolicyArtifact, + "ThreatCatalog": ThreatCatalogArtifact, + "VectorCatalog": VectorCatalogArtifact, + } + + entityTypeToString = map[EntityType]string{ + Human: "Human", + Software: "Software", + SoftwareAssisted: "Software Assisted", + } + + stringToEntityType = map[string]EntityType{ + "Human": Human, + "Software": Software, + "Software Assisted": SoftwareAssisted, + } + + entryTypeToString = map[EntryType]string{ + EntryTypeGuideline: "Guideline", + EntryTypeStatement: "Statement", + EntryTypeControl: "Control", + EntryTypeAssessmentRequirement: "AssessmentRequirement", + EntryTypeVector: "Vector", + } + + stringToEntryType = map[string]EntryType{ + "Guideline": EntryTypeGuideline, + "Statement": EntryTypeStatement, + "Control": EntryTypeControl, + "AssessmentRequirement": EntryTypeAssessmentRequirement, + "Vector": EntryTypeVector, + } + + confidenceLevelToString = map[ConfidenceLevel]string{ + Undetermined: "Undetermined", + Low: "Low", + Medium: "Medium", + High: "High", + } + + stringToConfidenceLevel = map[string]ConfidenceLevel{ + "Undetermined": Undetermined, + "Low": Low, + "Medium": Medium, + "High": High, + } + + relationshipTypeToString = map[RelationshipType]string{ + RelImplements: "implements", + RelImplementedBy: "implemented-by", + RelSupports: "supports", + RelSupportedBy: "supported-by", + RelEquivalent: "equivalent", + RelSubsumes: "subsumes", + RelNoMatch: "no-match", + RelRelatesTo: "relates-to", + } + + stringToRelationshipType = map[string]RelationshipType{ + "implements": RelImplements, + "implemented-by": RelImplementedBy, + "supports": RelSupports, + "supported-by": RelSupportedBy, + "equivalent": RelEquivalent, + "subsumes": RelSubsumes, + "no-match": RelNoMatch, + "relates-to": RelRelatesTo, + } + + methodTypeToString = map[MethodType]string{ + MethodManual: "Manual", + MethodBehavioral: "Behavioral", + MethodAutomated: "Automated", + MethodAutoremediation: "Autoremediation", + MethodGate: "Gate", + } + + stringToMethodType = map[string]MethodType{ + "Manual": MethodManual, + "Behavioral": MethodBehavioral, + "Automated": MethodAutomated, + "Autoremediation": MethodAutoremediation, + "Gate": MethodGate, + } + + severityToString = map[Severity]string{ + SeverityLow: "Low", + SeverityMedium: "Medium", + SeverityHigh: "High", + SeverityCritical: "Critical", + } + + stringToSeverity = map[string]Severity{ + "Low": SeverityLow, + "Medium": SeverityMedium, + "High": SeverityHigh, + "Critical": SeverityCritical, + } + + guidanceTypeToString = map[GuidanceType]string{ + GuidanceStandard: "Standard", + GuidanceRegulation: "Regulation", + GuidanceBestPractice: "Best Practice", + GuidanceFramework: "Framework", + } + + stringToGuidanceType = map[string]GuidanceType{ + "Standard": GuidanceStandard, + "Regulation": GuidanceRegulation, + "Best Practice": GuidanceBestPractice, + "Framework": GuidanceFramework, + } + + riskAppetiteToString = map[RiskAppetite]string{ + RiskAppetiteZero: "Zero", + RiskAppetiteLow: "Low", + RiskAppetiteModerate: "Moderate", + RiskAppetiteHigh: "High", + } + + stringToRiskAppetite = map[string]RiskAppetite{ + "Zero": RiskAppetiteZero, + "Low": RiskAppetiteLow, + "Moderate": RiskAppetiteModerate, + "High": RiskAppetiteHigh, + } + + modTypeToString = map[ModType]string{ + ModAdd: "Add", + ModModify: "Modify", + ModRemove: "Remove", + ModReplace: "Replace", + ModOverride: "Override", + } + + stringToModType = map[string]ModType{ + "Add": ModAdd, + "Modify": ModModify, + "Remove": ModRemove, + "Replace": ModReplace, + "Override": ModOverride, + } +) + +// enumStringer is used by marshal helpers. Implemented by all string-backed enums. +type enumStringer interface { + String() string +} + +func marshalYAMLString(s enumStringer) (interface{}, error) { + return s.String(), nil +} + +func marshalJSONString(s enumStringer) ([]byte, error) { + return json.Marshal(s.String()) +} + +func unmarshalYAMLEnum[T any](data []byte, m map[string]T, name string, dest *T) error { + var s string + if err := loaders.UnmarshalYAML(data, &s); err != nil { + return err + } + if val, ok := m[s]; ok { + *dest = val + return nil + } + return unknownEnumStringError(name, s, m) +} + +func unmarshalJSONEnum[T any](data []byte, m map[string]T, name string, dest *T) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + if val, ok := m[s]; ok { + *dest = val + return nil + } + return unknownEnumStringError(name, s, m) +} + +// unknownEnumStringError builds an error for an invalid enum string, including valid values. +func unknownEnumStringError[T any](name, got string, validMap map[string]T) error { + valid := make([]string, 0, len(validMap)) + for k := range validMap { + valid = append(valid, k) + } + sort.Strings(valid) + return fmt.Errorf("invalid %s: %q (valid: %s)", name, got, strings.Join(valid, ", ")) +} + +func (r Result) String() string { + if s, ok := toString[r]; ok { + return s + } + return fmt.Sprintf("Result(%d)", r) +} + +// MarshalYAML ensures that Result is serialized as a string in YAML +func (r Result) MarshalYAML() (interface{}, error) { + return marshalYAMLString(r) +} + +// MarshalJSON ensures that Result is serialized as a string in JSON +func (r Result) MarshalJSON() ([]byte, error) { + return marshalJSONString(r) +} + +// UnmarshalYAML ensures that Result can be deserialized from a YAML string +func (r *Result) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToResult, "Result", r) +} + +// UnmarshalJSON ensures that Result can be deserialized from a JSON string +func (r *Result) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToResult, "Result", r) +} + +func (a ArtifactType) String() string { + if s, ok := artifactTypeToString[a]; ok { + return s + } + return fmt.Sprintf("ArtifactType(%d)", a) +} + +// MarshalYAML ensures that ArtifactType is serialized as a string in YAML +func (a ArtifactType) MarshalYAML() (interface{}, error) { + return marshalYAMLString(a) +} + +// MarshalJSON ensures that ArtifactType is serialized as a string in JSON +func (a ArtifactType) MarshalJSON() ([]byte, error) { + return marshalJSONString(a) +} + +// UnmarshalYAML ensures that ArtifactType can be deserialized from a YAML string +func (a *ArtifactType) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToArtifactType, "ArtifactType", a) +} + +// UnmarshalJSON ensures that ArtifactType can be deserialized from a JSON string +func (a *ArtifactType) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToArtifactType, "ArtifactType", a) +} + +func (e EntityType) String() string { + if s, ok := entityTypeToString[e]; ok { + return s + } + return fmt.Sprintf("EntityType(%d)", e) +} + +// MarshalYAML ensures that EntityType is serialized as a string in YAML +func (e EntityType) MarshalYAML() (interface{}, error) { + return marshalYAMLString(e) +} + +// MarshalJSON ensures that EntityType is serialized as a string in JSON +func (e EntityType) MarshalJSON() ([]byte, error) { + return marshalJSONString(e) +} + +// UnmarshalYAML ensures that EntityType can be deserialized from a YAML string +func (e *EntityType) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToEntityType, "EntityType", e) +} + +// UnmarshalJSON ensures that EntityType can be deserialized from a JSON string +func (e *EntityType) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToEntityType, "EntityType", e) +} + +func (l Lifecycle) String() string { + if s, ok := lifecycleToString[l]; ok { + return s + } + return fmt.Sprintf("Lifecycle(%d)", l) +} + +// MarshalYAML ensures that Lifecycle is serialized as a string in YAML +func (l Lifecycle) MarshalYAML() (interface{}, error) { + return marshalYAMLString(l) +} + +// MarshalJSON ensures that Lifecycle is serialized as a string in JSON +func (l Lifecycle) MarshalJSON() ([]byte, error) { + return marshalJSONString(l) +} + +// UnmarshalYAML ensures that Lifecycle can be deserialized from a YAML string +func (l *Lifecycle) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToLifecycle, "Lifecycle", l) +} + +// UnmarshalJSON ensures that Lifecycle can be deserialized from a JSON string +func (l *Lifecycle) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToLifecycle, "Lifecycle", l) +} + +func (e EntryType) String() string { + if s, ok := entryTypeToString[e]; ok { + return s + } + return fmt.Sprintf("EntryType(%d)", e) +} + +// MarshalYAML ensures that EntryType is serialized as a string in YAML +func (e EntryType) MarshalYAML() (interface{}, error) { + return marshalYAMLString(e) +} + +// MarshalJSON ensures that EntryType is serialized as a string in JSON +func (e EntryType) MarshalJSON() ([]byte, error) { + return marshalJSONString(e) +} + +// UnmarshalYAML ensures that EntryType can be deserialized from a YAML string +func (e *EntryType) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToEntryType, "EntryType", e) +} + +// UnmarshalJSON ensures that EntryType can be deserialized from a JSON string +func (e *EntryType) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToEntryType, "EntryType", e) +} + +func (c ConfidenceLevel) String() string { + if s, ok := confidenceLevelToString[c]; ok { + return s + } + return fmt.Sprintf("ConfidenceLevel(%d)", c) +} + +// MarshalYAML ensures that ConfidenceLevel is serialized as a string in YAML +func (c ConfidenceLevel) MarshalYAML() (interface{}, error) { + return marshalYAMLString(c) +} + +// MarshalJSON ensures that ConfidenceLevel is serialized as a string in JSON +func (c ConfidenceLevel) MarshalJSON() ([]byte, error) { + return marshalJSONString(c) +} + +// UnmarshalYAML ensures that ConfidenceLevel can be deserialized from a YAML string +func (c *ConfidenceLevel) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToConfidenceLevel, "ConfidenceLevel", c) +} + +// UnmarshalJSON ensures that ConfidenceLevel can be deserialized from a JSON string +func (c *ConfidenceLevel) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToConfidenceLevel, "ConfidenceLevel", c) +} + +func (r RelationshipType) String() string { + if s, ok := relationshipTypeToString[r]; ok { + return s + } + return fmt.Sprintf("RelationshipType(%d)", r) +} + +// MarshalYAML ensures that RelationshipType is serialized as a string in YAML +func (r RelationshipType) MarshalYAML() (interface{}, error) { + return marshalYAMLString(r) +} + +// MarshalJSON ensures that RelationshipType is serialized as a string in JSON +func (r RelationshipType) MarshalJSON() ([]byte, error) { + return marshalJSONString(r) +} + +// UnmarshalYAML ensures that RelationshipType can be deserialized from a YAML string +func (r *RelationshipType) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToRelationshipType, "RelationshipType", r) +} + +// UnmarshalJSON ensures that RelationshipType can be deserialized from a JSON string +func (r *RelationshipType) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToRelationshipType, "RelationshipType", r) +} + +func (m MethodType) String() string { + if s, ok := methodTypeToString[m]; ok { + return s + } + return fmt.Sprintf("MethodType(%d)", m) +} + +// MarshalYAML ensures that MethodType is serialized as a string in YAML +func (m MethodType) MarshalYAML() (interface{}, error) { + return marshalYAMLString(m) +} + +// MarshalJSON ensures that MethodType is serialized as a string in JSON +func (m MethodType) MarshalJSON() ([]byte, error) { + return marshalJSONString(m) +} + +// UnmarshalYAML ensures that MethodType can be deserialized from a YAML string +func (m *MethodType) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToMethodType, "MethodType", m) +} + +// UnmarshalJSON ensures that MethodType can be deserialized from a JSON string +func (m *MethodType) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToMethodType, "MethodType", m) +} + +func (s Severity) String() string { + if str, ok := severityToString[s]; ok { + return str + } + return fmt.Sprintf("Severity(%d)", s) +} + +// MarshalYAML ensures that Severity is serialized as a string in YAML +func (s Severity) MarshalYAML() (interface{}, error) { + return marshalYAMLString(s) +} + +// MarshalJSON ensures that Severity is serialized as a string in JSON +func (s Severity) MarshalJSON() ([]byte, error) { + return marshalJSONString(s) +} + +// UnmarshalYAML ensures that Severity can be deserialized from a YAML string +func (s *Severity) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToSeverity, "Severity", s) +} + +// UnmarshalJSON ensures that Severity can be deserialized from a JSON string +func (s *Severity) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToSeverity, "Severity", s) +} + +func (g GuidanceType) String() string { + if s, ok := guidanceTypeToString[g]; ok { + return s + } + return fmt.Sprintf("GuidanceType(%d)", g) +} + +// MarshalYAML ensures that GuidanceType is serialized as a string in YAML +func (g GuidanceType) MarshalYAML() (interface{}, error) { + return marshalYAMLString(g) +} + +// MarshalJSON ensures that GuidanceType is serialized as a string in JSON +func (g GuidanceType) MarshalJSON() ([]byte, error) { + return marshalJSONString(g) +} + +// UnmarshalYAML ensures that GuidanceType can be deserialized from a YAML string +func (g *GuidanceType) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToGuidanceType, "GuidanceType", g) +} + +// UnmarshalJSON ensures that GuidanceType can be deserialized from a JSON string +func (g *GuidanceType) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToGuidanceType, "GuidanceType", g) +} + +func (r RiskAppetite) String() string { + if s, ok := riskAppetiteToString[r]; ok { + return s + } + return fmt.Sprintf("RiskAppetite(%d)", r) +} + +// MarshalYAML ensures that RiskAppetite is serialized as a string in YAML +func (r RiskAppetite) MarshalYAML() (interface{}, error) { + return marshalYAMLString(r) +} + +// MarshalJSON ensures that RiskAppetite is serialized as a string in JSON +func (r RiskAppetite) MarshalJSON() ([]byte, error) { + return marshalJSONString(r) +} + +// UnmarshalYAML ensures that RiskAppetite can be deserialized from a YAML string +func (r *RiskAppetite) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToRiskAppetite, "RiskAppetite", r) +} + +// UnmarshalJSON ensures that RiskAppetite can be deserialized from a JSON string +func (r *RiskAppetite) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToRiskAppetite, "RiskAppetite", r) +} + +func (m ModType) String() string { + if s, ok := modTypeToString[m]; ok { + return s + } + return fmt.Sprintf("ModType(%d)", m) +} + +// MarshalYAML ensures that ModType is serialized as a string in YAML +func (m ModType) MarshalYAML() (interface{}, error) { + return marshalYAMLString(m) +} + +// MarshalJSON ensures that ModType is serialized as a string in JSON +func (m ModType) MarshalJSON() ([]byte, error) { + return marshalJSONString(m) +} + +// UnmarshalYAML ensures that ModType can be deserialized from a YAML string +func (m *ModType) UnmarshalYAML(data []byte) error { + return unmarshalYAMLEnum(data, stringToModType, "ModType", m) +} + +// UnmarshalJSON ensures that ModType can be deserialized from a JSON string +func (m *ModType) UnmarshalJSON(data []byte) error { + return unmarshalJSONEnum(data, stringToModType, "ModType", m) +} + +// UpdateAggregateResult compares the current result with the new result and returns the most severe of the two. +func UpdateAggregateResult(previous Result, new Result) Result { + if new == NotRun { + // Not Run should not overwrite anything + // Failed should not be overwritten by anything + // Failed should overwrite anything + return previous + } + + if previous == Failed || new == Failed { + // Failed should not be overwritten by anything + // Failed should overwrite anything + return Failed + } + + if previous == Unknown || new == Unknown { + // If the current or past result is Unknown, it should not be overwritten by NeedsReview or Passed. + return Unknown + } + + if previous == NeedsReview || new == NeedsReview { + // NeedsReview should not be overwritten by Passed + // NeedsReview should overwrite Passed + return NeedsReview + } + return Passed +} diff --git a/vendor/github.com/gemaraproj/go-gemara/gemaraconv/catalog.go b/vendor/github.com/gemaraproj/go-gemara/gemaraconv/catalog.go index 5907bf33..450a6982 100644 --- a/vendor/github.com/gemaraproj/go-gemara/gemaraconv/catalog.go +++ b/vendor/github.com/gemaraproj/go-gemara/gemaraconv/catalog.go @@ -34,7 +34,7 @@ func CatalogToOSCAL(catalog *gemara.ControlCatalog, opts ...GenerateOption) (osc Metadata: metadata, } - familyMap := make(map[string]gemara.Family) + familyMap := make(map[string]gemara.Group) for _, family := range catalog.Families { familyMap[family.Id] = family } diff --git a/vendor/github.com/gemaraproj/go-gemara/gemaraconv/guidance.go b/vendor/github.com/gemaraproj/go-gemara/gemaraconv/guidance.go index 5bff33bd..0b918602 100644 --- a/vendor/github.com/gemaraproj/go-gemara/gemaraconv/guidance.go +++ b/vendor/github.com/gemaraproj/go-gemara/gemaraconv/guidance.go @@ -116,11 +116,11 @@ func GuidanceToOSCAL(g *gemara.GuidanceCatalog, guidanceDocHref string, opts ... return catalog, profile, nil } -func createControlGroup(g *gemara.GuidanceCatalog, family gemara.Family, guidelines []gemara.Guideline, resourcesMap map[string]string) oscal.Group { - group := oscal.Group{ +func createControlGroup(g *gemara.GuidanceCatalog, group gemara.Group, guidelines []gemara.Guideline, resourcesMap map[string]string) oscal.Group { + oscalGroup := oscal.Group{ Class: "family", - ID: family.Id, - Title: family.Title, + ID: group.Id, + Title: group.Title, } controlMap := make(map[string]oscal.Control) @@ -199,8 +199,8 @@ func createControlGroup(g *gemara.GuidanceCatalog, family gemara.Family, guideli } } - group.Controls = oscalUtils.NilIfEmpty(controls) - return group + oscalGroup.Controls = oscalUtils.NilIfEmpty(controls) + return oscalGroup } // guidelineToParts converts a guideline to OSCAL parts that can be added to an existing control. @@ -309,8 +309,8 @@ func guidelineToControl(g *gemara.GuidanceCatalog, guideline gemara.Guideline, r links = append(links, relatedLink) } - guidanceLinks := mappingToLinks(guideline.GuidelineMappings, resourcesMap) - principleLinks := mappingToLinks(guideline.PrincipleMappings, resourcesMap) + guidanceLinks := mappingToLinks(guideline.Vectors, resourcesMap) + principleLinks := mappingToLinks(guideline.Principles, resourcesMap) links = append(links, guidanceLinks...) links = append(links, principleLinks...) control.Links = oscalUtils.NilIfEmpty(links) diff --git a/vendor/github.com/gemaraproj/go-gemara/gemaraconv/test-data.go b/vendor/github.com/gemaraproj/go-gemara/gemaraconv/test-data.go index 82cedd62..2a9f93c6 100644 --- a/vendor/github.com/gemaraproj/go-gemara/gemaraconv/test-data.go +++ b/vendor/github.com/gemaraproj/go-gemara/gemaraconv/test-data.go @@ -41,8 +41,8 @@ func guidanceWithExternalExtends() gemara.GuidanceCatalog { }, }, }, - GuidanceType: "Framework", - Families: []gemara.Family{ + GuidanceType: gemara.GuidanceFramework, + Families: []gemara.Group{ { Id: "AC", Title: "Access Control", @@ -91,8 +91,8 @@ func guidanceWithMerging() gemara.GuidanceCatalog { }, }, }, - GuidanceType: "Framework", - Families: []gemara.Family{ + GuidanceType: gemara.GuidanceFramework, + Families: []gemara.Group{ { Id: "AC", Title: "Access Control", @@ -148,8 +148,8 @@ func guidanceWithLocalExtends() gemara.GuidanceCatalog { Type: gemara.Human, }, }, - GuidanceType: gemara.GuidanceType("Framework"), - Families: []gemara.Family{ + GuidanceType: gemara.GuidanceFramework, + Families: []gemara.Group{ { Id: "AC", Title: "Access Control", @@ -187,8 +187,8 @@ func guidanceWithMultiLevelNested() gemara.GuidanceCatalog { Type: gemara.Human, }, }, - GuidanceType: gemara.GuidanceType("Framework"), - Families: []gemara.Family{ + GuidanceType: gemara.GuidanceFramework, + Families: []gemara.Group{ { Id: "AC", Title: "Access Control", diff --git a/vendor/github.com/gemaraproj/go-gemara/generated_types.go b/vendor/github.com/gemaraproj/go-gemara/generated_types.go index 5924dc90..2d8dbbc9 100644 --- a/vendor/github.com/gemaraproj/go-gemara/generated_types.go +++ b/vendor/github.com/gemaraproj/go-gemara/generated_types.go @@ -17,73 +17,25 @@ type Contact struct { Social *string `json:"social,omitempty" yaml:"social,omitempty"` } -// Actor represents an entity (human or tool) that can perform actions in evaluations -type Actor struct { - // id uniquely identifies the actor and allows this entry to be referenced by other elements - Id string `json:"id" yaml:"id"` - - // name is the name of the actor - Name string `json:"name" yaml:"name"` - - // type specifies the type of entity interacting in the workflow - Type ActorType `json:"type" yaml:"type"` - - // version is the version of the actor (for tools; if applicable) - Version string `json:"version,omitempty" yaml:"version,omitempty"` - - // description provides additional context about the actor - Description string `json:"description,omitempty" yaml:"description,omitempty"` - - // uri is a general URI for the actor information - Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` - - // contact is contact information for the actor - Contact Contact `json:"contact,omitempty" yaml:"contact,omitempty"` -} - -// Email represents a validated email address pattern -type Email string - -// Datetime represents an ISO 8601 formatted datetime string -type Datetime string - -// Date represents a date string (ISO 8601 date format) -type Date string - -// Category represents a category used for applicability or classification -type Category struct { - // id allows this entry to be referenced by other elements - Id string `json:"id" yaml:"id"` - - // title describes the purpose of this category at a glance - Title string `json:"title" yaml:"title"` - - // description explains the significance and traits of entries to this category - Description string `json:"description" yaml:"description"` -} - -// GuidanceCatalog represents a concerted documentation effort to help bring about an optimal future without foreknowledge of the implementation details -type GuidanceCatalog struct { +// ControlCatalog describes a set of related controls and relevant metadata +type ControlCatalog struct { // title describes the contents of this catalog at a glance Title string `json:"title" yaml:"title"` // metadata provides detailed data about this catalog Metadata Metadata `json:"metadata" yaml:"metadata"` - // type categorizes this document based on the intent of its contents - GuidanceType GuidanceType `json:"type" yaml:"type"` + // extends references control catalogs that this catalog builds upon + Extends []ArtifactMapping `json:"extends,omitempty" yaml:"extends,omitempty"` - // front-matter provides introductory text for the document to be used during rendering - FrontMatter string `json:"front-matter,omitempty" yaml:"front-matter,omitempty"` - - // families contains a list of guidance families that can be referenced by guidance - Families []Family `json:"families,omitempty" yaml:"families,omitempty"` + // families contains a list of control families that can be referenced by controls + Families []Group `json:"families,omitempty" yaml:"families,omitempty"` - // guidelines is a list of unique guidelines defined by this catalog - Guidelines []Guideline `json:"guidelines,omitempty" yaml:"guidelines,omitempty"` + // controls is a list of unique controls defined by this catalog + Controls []Control `json:"controls,omitempty" yaml:"controls,omitempty"` - // exemptions provides information about situations where this guidance is not applicable - Exemptions []Exemption `json:"exemptions,omitempty" yaml:"exemptions,omitempty"` + // imports contains controls from other sources which are included as part of this document + Imports ControlCatalogImports `json:"imports,omitempty" yaml:"imports,omitempty"` } // Metadata represents common metadata fields shared across all layers @@ -91,11 +43,17 @@ type Metadata struct { // id allows this entry to be referenced by other elements Id string `json:"id" yaml:"id"` + // type identifies the kind of Gemara artifact for unambiguous parsing + Type ArtifactType `json:"type" yaml:"type"` + + // gemara-version declares which version of the Gemara specification this artifact conforms to + GemaraVersion string `json:"gemara-version" yaml:"gemara-version"` + // version is the version identifier of this artifact Version string `json:"version,omitempty" yaml:"version,omitempty"` // date is the publication or effective date of this artifact - Date Date `json:"date,omitempty" yaml:"date,omitempty"` + Date Datetime `json:"date,omitempty" yaml:"date,omitempty"` // description provides a high-level summary of the artifact's purpose and scope Description string `json:"description" yaml:"description"` @@ -107,7 +65,7 @@ type Metadata struct { MappingReferences []MappingReference `json:"mapping-references,omitempty" yaml:"mapping-references,omitempty"` // applicability-categories is a list of categories used to classify within this artifact to specify scope - ApplicabilityCategories []Category `json:"applicability-categories,omitempty" yaml:"applicability-categories,omitempty"` + ApplicabilityCategories []Group `json:"applicability-categories,omitempty" yaml:"applicability-categories,omitempty"` // draft indicates whether this artifact is a pre-release version; open to modification Draft bool `json:"draft,omitempty" yaml:"draft,omitempty"` @@ -116,6 +74,33 @@ type Metadata struct { Lexicon *ArtifactMapping `json:"lexicon,omitempty" yaml:"lexicon,omitempty"` } +// Datetime represents an ISO 8601 formatted datetime string +type Datetime string + +// Actor represents an entity (human or tool) that performs actions in evaluations +type Actor struct { + // contact is contact information for the actor + Contact Contact `json:"contact,omitempty" yaml:"contact,omitempty"` + + // id uniquely identifies the entity and allows this entry to be referenced by other elements + Id string `json:"id" yaml:"id"` + + // name is the name of the entity + Name string `json:"name" yaml:"name"` + + // type specifies the type of entity interacting in the workflow + Type EntityType `json:"type" yaml:"type"` + + // version is the version of the entity (for tools; if applicable) + Version string `json:"version,omitempty" yaml:"version,omitempty"` + + // description provides additional context about the entity + Description string `json:"description,omitempty" yaml:"description,omitempty"` + + // uri is a general URI for the entity information + Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` +} + // MappingReference represents a reference to an external document with full metadata. type MappingReference struct { // id allows this entry to be referenced by other elements @@ -134,27 +119,249 @@ type MappingReference struct { Url string `json:"url,omitempty" yaml:"url,omitempty"` } +// Group represents a classification or grouping that can be used in different contexts with semantic meaning derived from its usage +type Group struct { + // id allows this entry to be referenced by other elements + Id string `json:"id" yaml:"id"` + + // title describes the purpose of this group at a glance + Title string `json:"title" yaml:"title"` + + // description explains the significance and traits of entries to this group + Description string `json:"description" yaml:"description"` +} + type ArtifactMapping struct { // ReferenceId should reference the corresponding MappingReference id from metadata ReferenceId string `json:"reference-id" yaml:"reference-id"` // remarks is prose regarding the mapped artifact or the mapping relationship - Remarks string `json:"remarks" yaml:"remarks"` + Remarks string `json:"remarks,omitempty" yaml:"remarks,omitempty"` } -// GuidanceType restricts the possible types that a catalog may be listed as -type GuidanceType string - -// Family represents a logical grouping of guidelines or controls which share a common purpose or function -type Family struct { +// Control describes a safeguard or countermeasure with a clear objective and assessment requirements +type Control struct { // id allows this entry to be referenced by other elements Id string `json:"id" yaml:"id"` - // title describes the purpose of this family at a glance + // title describes the purpose of this control at a glance Title string `json:"title" yaml:"title"` - // description explains the significance and traits of entries to this entity family + // objective is a unified statement of intent, which may encompass multiple situationally applicable requirements + Objective string `json:"objective" yaml:"objective"` + + // family references by id a catalog control family that this control belongs to + Family string `json:"family" yaml:"family"` + + // assessment-requirements is a list of requirements that must be verified to confirm the control objective has been met + AssessmentRequirements []AssessmentRequirement `json:"assessment-requirements" yaml:"assessment-requirements"` + + // guidelines documents relationships between this control and Layer 1 guideline artifacts + Guidelines []MultiEntryMapping `json:"guidelines,omitempty" yaml:"guidelines,omitempty"` + + // threats documents relationships between this control and Layer 2 threat artifacts + Threats []MultiEntryMapping `json:"threats,omitempty" yaml:"threats,omitempty"` + + // state is the lifecycle state of this control + State Lifecycle `json:"state" yaml:"state"` + + // replaced-by references the control that supersedes this one when deprecated or retired + ReplacedBy *EntryMapping `json:"replaced-by,omitempty" yaml:"replaced-by,omitempty"` +} + +// AssessmentRequirement describes a tightly scoped, verifiable condition that must be satisfied and confirmed by an evaluator +type AssessmentRequirement struct { + // id allows this entry to be referenced by other elements + Id string `json:"id" yaml:"id"` + + // text is the body of the requirement, typically written as a MUST condition + Text string `json:"text" yaml:"text"` + + // applicability is a list of strings describing the situations where this text functions as a requirement for its parent control + Applicability []string `json:"applicability" yaml:"applicability"` + + // recommendation provides readers with non-binding suggestions to aid in evaluation or enforcement of the requirement + Recommendation string `json:"recommendation,omitempty" yaml:"recommendation,omitempty"` + + // state is the lifecycle state of this assessment requirement + State Lifecycle `json:"state" yaml:"state"` + + // replaced-by references the assessment requirement that supersedes this one when deprecated or retired + ReplacedBy *EntryMapping `json:"replaced-by,omitempty" yaml:"replaced-by,omitempty"` +} + +// EntryMapping represents how a specific entry (control/requirement/procedure) maps to a MappingReference. +type EntryMapping struct { + // reference-id is the id for a MappingReference entry in the artifact's metadata + ReferenceId string `json:"reference-id,omitempty" yaml:"reference-id,omitempty"` + + // entry-id is the identifier being mapped to in the referenced artifact + EntryId string `json:"entry-id" yaml:"entry-id"` + + // remarks is prose describing the mapping relationship + Remarks string `json:"remarks,omitempty" yaml:"remarks,omitempty"` +} + +// MultiEntryMapping represents a mapping to an external reference with one or more entries. +type MultiEntryMapping struct { + // ReferenceId should reference the corresponding MappingReference id from metadata + ReferenceId string `json:"reference-id" yaml:"reference-id"` + + // entries is a list of mapping entries + Entries []MappingEntry `json:"entries" yaml:"entries"` + + // remarks is prose regarding the mapped artifact or the mapping relationship + Remarks string `json:"remarks,omitempty" yaml:"remarks,omitempty"` +} + +// MappingEntry represents a single entry within a mapping +type MappingEntry struct { + // reference-id is the id for a MappingReference entry in the artifact's metadata + ReferenceId string `json:"reference-id" yaml:"reference-id"` + + // remarks is prose describing the mapping relationship + Remarks string `json:"remarks,omitempty" yaml:"remarks,omitempty"` +} + +// ControlCatalogImports defines imported entries for a control catalog +type ControlCatalogImports struct { + // controls is a list of controls from another source + Controls []MultiEntryMapping `json:"controls,omitempty" yaml:"controls,omitempty"` +} + +// Entity represents a human or tool +type Entity struct { + // id uniquely identifies the entity and allows this entry to be referenced by other elements + Id string `json:"id" yaml:"id"` + + // name is the name of the entity + Name string `json:"name" yaml:"name"` + + // type specifies the type of entity interacting in the workflow + Type EntityType `json:"type" yaml:"type"` + + // version is the version of the entity (for tools; if applicable) + Version string `json:"version,omitempty" yaml:"version,omitempty"` + + // description provides additional context about the entity + Description string `json:"description,omitempty" yaml:"description,omitempty"` + + // uri is a general URI for the entity information + Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` +} + +// EvaluationLog contains the results of evaluating a set of Layer 2 controls. +type EvaluationLog struct { + Metadata Metadata `json:"metadata" yaml:"metadata"` + + Evaluations []*ControlEvaluation `json:"evaluations" yaml:"evaluations"` + + Target Resource `json:"target" yaml:"target"` +} + +// Resource represents an entity that exists in the system and can be evaluated +type Resource struct { + // environment describes where the resource exists (e.g., production, staging, development, specific region) + Environment string `json:"environment,omitempty" yaml:"environment,omitempty"` + + // id uniquely identifies the entity and allows this entry to be referenced by other elements + Id string `json:"id" yaml:"id"` + + // name is the name of the entity + Name string `json:"name" yaml:"name"` + + // owner is the contact information for the person or group responsible for managing or owning this resource + Owner Contact `json:"owner,omitempty" yaml:"owner,omitempty"` + + // type specifies the type of entity interacting in the workflow + Type EntityType `json:"type" yaml:"type"` + + // version is the version of the entity (for tools; if applicable) + Version string `json:"version,omitempty" yaml:"version,omitempty"` + + // description provides additional context about the entity + Description string `json:"description,omitempty" yaml:"description,omitempty"` + + // uri is a general URI for the entity information + Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` +} + +// ControlEvaluation contains the results of evaluating a single Layer 5 control. +type ControlEvaluation struct { + Name string `json:"name" yaml:"name"` + + Result Result `json:"result" yaml:"result"` + + Message string `json:"message" yaml:"message"` + + Control EntryMapping `json:"control" yaml:"control"` + + // Enforce that control reference and the assessments' references match + // This formulation uses the control's reference if the assessment doesn't include a reference + AssessmentLogs []*AssessmentLog `json:"assessment-logs" yaml:"assessment-logs"` +} + +// AssessmentLog contains the results of executing a single assessment procedure for a control requirement. +type AssessmentLog struct { + // Requirement should map to the assessment requirement for this assessment. + Requirement EntryMapping `json:"requirement" yaml:"requirement"` + + // Plan maps to the policy assessment plan being executed. + Plan *EntryMapping `json:"plan,omitempty" yaml:"plan,omitempty"` + + // Description provides a summary of the assessment procedure. Description string `json:"description" yaml:"description"` + + // Result is the overall outcome of the assessment procedure, matching the result of the last step that was run. + Result Result `json:"result" yaml:"result"` + + // Message provides additional context about the assessment result. + Message string `json:"message" yaml:"message"` + + // Applicability is elevated from the Layer 2 Assessment Requirement to aid in execution and reporting. + Applicability []string `json:"applicability" yaml:"applicability"` + + // Steps are sequential actions taken as part of the assessment, which may halt the assessment if a failure occurs. + Steps []AssessmentStep `json:"steps" yaml:"steps"` + + // Steps-executed is the number of steps that were executed as part of the assessment. + StepsExecuted int64 `json:"steps-executed,omitempty" yaml:"steps-executed,omitempty"` + + // Start is the timestamp when the assessment began. + Start Datetime `json:"start" yaml:"start"` + + // End is the timestamp when the assessment concluded. + End Datetime `json:"end,omitempty" yaml:"end,omitempty"` + + // Recommendation provides guidance on how to address a failed assessment. + Recommendation string `json:"recommendation,omitempty" yaml:"recommendation,omitempty"` + + // ConfidenceLevel indicates the evaluator's confidence level in this specific assessment result. + ConfidenceLevel ConfidenceLevel `json:"confidence-level,omitempty" yaml:"confidence-level,omitempty"` +} + +// GuidanceCatalog represents a concerted documentation effort to help bring about an optimal future without foreknowledge of the implementation details +type GuidanceCatalog struct { + // title describes the contents of this catalog at a glance + Title string `json:"title" yaml:"title"` + + // metadata provides detailed data about this catalog + Metadata Metadata `json:"metadata" yaml:"metadata"` + + // type categorizes this document based on the intent of its contents + GuidanceType GuidanceType `json:"type" yaml:"type"` + + // front-matter provides introductory text for the document to be used during rendering + FrontMatter string `json:"front-matter,omitempty" yaml:"front-matter,omitempty"` + + // families contains a list of guidance families that can be referenced by guidance + Families []Group `json:"families,omitempty" yaml:"families,omitempty"` + + // guidelines is a list of unique guidelines defined by this catalog + Guidelines []Guideline `json:"guidelines,omitempty" yaml:"guidelines,omitempty"` + + // exemptions provides information about situations where this guidance is not applicable + Exemptions []Exemption `json:"exemptions,omitempty" yaml:"exemptions,omitempty"` } // Guideline provides explanatory context and recommendations for designing optimal outcomes @@ -186,33 +393,20 @@ type Guideline struct { // statements is a list of structural sub-requirements within a guideline Statements []Statement `json:"statements,omitempty" yaml:"statements,omitempty"` - // guideline-mappings documents the relationship between this guideline and external guidelines - GuidelineMappings []MultiEntryMapping `json:"guideline-mappings,omitempty" yaml:"guideline-mappings,omitempty"` - - // principle-mappings documents the relationship between this guideline and one or more principles - PrincipleMappings []MultiEntryMapping `json:"principle-mappings,omitempty" yaml:"principle-mappings,omitempty"` + // principles documents the relationship between this guideline and one or more principles + Principles []MultiEntryMapping `json:"principles,omitempty" yaml:"principles,omitempty"` // vector-mappings documents the relationship between this guideline and one or more vectors - VectorMappings []MultiEntryMapping `json:"vector-mappings,omitempty" yaml:"vector-mappings,omitempty"` + Vectors []MultiEntryMapping `json:"vectors,omitempty" yaml:"vectors,omitempty"` // see-also lists related guideline IDs within the same GuidanceCatalog SeeAlso []string `json:"see-also,omitempty" yaml:"see-also,omitempty"` -} -// EntryMapping represents how a specific entry (control/requirement/procedure) maps to a MappingReference. -type EntryMapping struct { - // reference-id is the id for a MappingReference entry in the artifact's metadata - ReferenceId string `json:"reference-id,omitempty" yaml:"reference-id,omitempty"` - - // entry-id is the identifier being mapped to in the referenced artifact - EntryId string `json:"entry-id" yaml:"entry-id"` + // state is the lifecycle state of this guideline + State Lifecycle `json:"state" yaml:"state"` - // strength is the author's estimate of how completely the current/source material satisfies the target/reference material; - // Range: 1-10. Zero value means not yet quantified. - Strength int64 `json:"strength,omitempty" yaml:"strength,omitempty"` - - // remarks is prose describing the mapping relationship - Remarks string `json:"remarks,omitempty" yaml:"remarks,omitempty"` + // replaced-by references the guideline that supersedes this one when deprecated or retired + ReplacedBy *EntryMapping `json:"replaced-by,omitempty" yaml:"replaced-by,omitempty"` } // Rationale provides a structured way to communicate a guideline author's intent @@ -240,31 +434,6 @@ type Statement struct { Recommendations []string `json:"recommendations,omitempty" yaml:"recommendations,omitempty"` } -// MultiEntryMapping represents a mapping to an external reference with one or more entries. -type MultiEntryMapping struct { - // ReferenceId should reference the corresponding MappingReference id from metadata - ReferenceId string `json:"reference-id" yaml:"reference-id"` - - // entries is a list of mapping entries - Entries []MappingEntry `json:"entries" yaml:"entries"` - - // remarks is prose regarding the mapped artifact or the mapping relationship - Remarks string `json:"remarks,omitempty" yaml:"remarks,omitempty"` -} - -// MappingEntry represents a single entry within a mapping -type MappingEntry struct { - // reference-id is the id for a MappingReference entry in the artifact's metadata - ReferenceId string `json:"reference-id" yaml:"reference-id"` - - // strength is the author's estimate of how completely the current/source material satisfies the target/reference material; - // Range: 1-10. Zero value means not yet quantified. - Strength int64 `json:"strength,omitempty" yaml:"strength,omitempty"` - - // remarks is prose describing the mapping relationship - Remarks string `json:"remarks,omitempty" yaml:"remarks,omitempty"` -} - // Exemption describes a single scenario where the catalog is not applicable type Exemption struct { // description identifies who or what is exempt from the full guidance @@ -277,115 +446,137 @@ type Exemption struct { Redirect *MultiEntryMapping `json:"redirect,omitempty" yaml:"redirect,omitempty"` } -// ControlCatalog describes a set of related controls and relevant metadata -type ControlCatalog struct { - // title describes the contents of this catalog at a glance +// MappingDocument captures the user's intent for how entries in a source artifact relate to entries in a target artifact +type MappingDocument struct { + // title describes the purpose of this mapping document at a glance Title string `json:"title" yaml:"title"` - // metadata provides detailed data about this catalog + // metadata provides detailed data about this document Metadata Metadata `json:"metadata" yaml:"metadata"` - // families contains a list of control families that can be referenced by controls - Families []Family `json:"families,omitempty" yaml:"families,omitempty"` + // source-reference identifies the artifact being mapped from; must match a mapping-reference id + SourceReference ArtifactMapping `json:"source-reference" yaml:"source-reference"` - // controls is a list of unique controls defined by this catalog - Controls []Control `json:"controls,omitempty" yaml:"controls,omitempty"` + // target-reference identifies the artifact being mapped to; must match a mapping-reference id + TargetReference ArtifactMapping `json:"target-reference" yaml:"target-reference"` + + // mappings is one or more atomic relationships between entries in the referenced artifacts + Mappings []Mapping `json:"mappings" yaml:"mappings"` - // imported-controls is a list of controls from another source which are included as part of this document - ImportedControls []MultiEntryMapping `json:"imported-controls,omitempty" yaml:"imported-controls,omitempty"` + // remarks is prose regarding this mapping document + Remarks string `json:"remarks,omitempty" yaml:"remarks,omitempty"` } -// Control describes a safeguard or countermeasure with a clear objective and assessment requirements -type Control struct { - // id allows this entry to be referenced by other elements +// Mapping represents an atomic relationship between a source entry and an optional target entry +type Mapping struct { + // id allows this mapping to be referenced by other elements Id string `json:"id" yaml:"id"` - // title describes the purpose of this control at a glance - Title string `json:"title" yaml:"title"` + // source identifies the entry being mapped from + Source EntryReference `json:"source" yaml:"source"` - // objective is a unified statement of intent, which may encompass multiple situationally applicable requirements - Objective string `json:"objective" yaml:"objective"` + // target identifies the entry being mapped to; absent when relationship is no-match + Target *EntryReference `json:"target,omitempty" yaml:"target,omitempty"` - // family references by id a catalog control family that this control belongs to - Family string `json:"family" yaml:"family"` + // relationship describes the nature or purpose of the mapping + Relationship RelationshipType `json:"relationship" yaml:"relationship"` - // assessment-requirements is a list of requirements that must be verified to confirm the control objective has been met - AssessmentRequirements []AssessmentRequirement `json:"assessment-requirements" yaml:"assessment-requirements"` + ConfidenceLevel ConfidenceLevel `json:"confidence-level,omitempty" yaml:"confidence-level,omitempty"` + + // applicability constrains the contexts in which this mapping holds + Applicability []string `json:"applicability,omitempty" yaml:"applicability,omitempty"` - // guideline-mappings documents relationships betwen this control and Layer 1 guideline artifacts - GuidelineMappings []MultiEntryMapping `json:"guideline-mappings,omitempty" yaml:"guideline-mappings,omitempty"` + // rationale explains why this relationship exists + Rationale string `json:"rationale,omitempty" yaml:"rationale,omitempty"` - // threat-mappings documents relationships betwen this control and Layer 2 threat artifacts - ThreatMappings []MultiEntryMapping `json:"threat-mappings,omitempty" yaml:"threat-mappings,omitempty"` + // remarks is general prose regarding this mapping + Remarks string `json:"remarks,omitempty" yaml:"remarks,omitempty"` } -// AssessmentRequirement describes a tightly scoped, verifiable condition that must be satisfied and confirmed by an evaluator -type AssessmentRequirement struct { - // id allows this entry to be referenced by other elements - Id string `json:"id" yaml:"id"` +// EntryReference identifies a specific entry within a referenced artifact +type EntryReference struct { + // entry-id identifies the specific entry in the referenced artifact + EntryId string `json:"entry-id" yaml:"entry-id"` - // text is the body of the requirement, typically written as a MUST condition - Text string `json:"text" yaml:"text"` + // entry-type identifies what kind of atomic unit this entry is + EntryType EntryType `json:"entry-type" yaml:"entry-type"` +} - // applicability is a list of strings describing the situations where this text functions as a requirement for its parent control - Applicability []string `json:"applicability" yaml:"applicability"` +// Email represents a validated email address pattern +type Email string - // recommendation provides readers with non-binding suggestions to aid in evaluation or enforcement of the requirement - Recommendation string `json:"recommendation,omitempty" yaml:"recommendation,omitempty"` +// Owner defines the RACI roles responsible for managing an artifact such as a risk +type RACI struct { + // responsible identifies the entities responsible for executing work to manage or mitigate the artifact + Responsible []Contact `json:"responsible" yaml:"responsible"` + + // accountable identifies the entity ultimately accountable for the outcome + Accountable []Contact `json:"accountable" yaml:"accountable"` + + // consulted identifies entities whose input is required when assessing or responding to the artifact + Consulted []Contact `json:"consulted,omitempty" yaml:"consulted,omitempty"` + + // informed identifies entities that should be notified about changes to the artifact status + Informed []Contact `json:"informed,omitempty" yaml:"informed,omitempty"` } -// ThreatCatalog describes a set of topically-associated threats -type ThreatCatalog struct { - // title describes the purpose of this catalog at a glance +// A RiskCatalog is a structured collection of documented risks that may affect an organization, +// system, or service. It provides a centralized reference for risks that can be mapped to threats +// and referenced by policies when documenting how those risks are mitigated or accepted. +type RiskCatalog struct { + // title describes the contents of this catalog at a glance Title string `json:"title" yaml:"title"` // metadata provides detailed data about this catalog Metadata Metadata `json:"metadata" yaml:"metadata"` - // threats is a list of threats defined by this catalog - Threats []Threat `json:"threats,omitempty" yaml:"threats,omitempty"` - - // capabilities is a list of capabilities that make up the system being assessed - Capabilities []Capability `json:"capabilities,omitempty" yaml:"capabilities,omitempty"` - - // imported-threats is a list of threats from another source which are included as part of this document - ImportedThreats []MultiEntryMapping `json:"imported-threats,omitempty" yaml:"imported-threats,omitempty"` + // categories is a list of risk categories used to classify risks + Categories []RiskCategory `json:"categories,omitempty" yaml:"categories,omitempty"` - // imported-capabilities is a list of capabilities from another source which are included as part of this document - ImportedCapabilities []MultiEntryMapping `json:"imported-capabilities,omitempty" yaml:"imported-capabilities,omitempty"` + // risks is a list of risks defined by this catalog + Risks []Risk `json:"risks,omitempty" yaml:"risks,omitempty"` } -// Threat describes a specifically-scoped opportunity for a negative impact to the organization -type Threat struct { +// RiskCategory describes a grouping of risks and defines appetite boundaries +type RiskCategory struct { + // appetite defines the acceptable level of risk for this category + Appetite RiskAppetite `json:"appetite" yaml:"appetite"` + // id allows this entry to be referenced by other elements Id string `json:"id" yaml:"id"` - // title describes this threat at a glance + // max-severity defines the highest allowed severity within this category + MaxSeverity Severity `json:"max-severity,omitempty" yaml:"max-severity,omitempty"` + + // title describes the purpose of this group at a glance Title string `json:"title" yaml:"title"` - // description provides a detailed explanation of an opportunity for negative impact + // description explains the significance and traits of entries to this group Description string `json:"description" yaml:"description"` - - // capabilities documents the relationship between this threat and a system capability - Capabilities []MultiEntryMapping `json:"capabilities" yaml:"capabilities"` - - // actors describes the relevant internal or external threat actors - Actors []Actor `json:"actors,omitempty" yaml:"actors,omitempty"` - - // external-mappings documents relationships between this threat and any other artifacts - ExternalMappings []MultiEntryMapping `json:"external-mappings,omitempty" yaml:"external-mappings,omitempty"` } -// Capability describes a system capability such as a feature, component or object. -type Capability struct { - // id allows this entry to be referenced by other elements +// A Risk represents the potential for negative impact resulting from one or more threats. +type Risk struct { + // id allows this risk to be referenced by other elements Id string `json:"id" yaml:"id"` - // title describes this capability at a glance + // title describes the risk Title string `json:"title" yaml:"title"` - // description provides a detailed overview of this capability + // description explains the risk scenario Description string `json:"description" yaml:"description"` + + // severity describes the impact level + Severity Severity `json:"severity" yaml:"severity"` + + // owner defines the RACI roles responsible for managing this risk + Owner RACI `json:"owner,omitempty" yaml:"owner,omitempty"` + + // impact describes the business or operational impact + Impact string `json:"impact,omitempty" yaml:"impact,omitempty"` + + // threats link this risk to Layer 2 threats + Threats []MultiEntryMapping `json:"threats,omitempty" yaml:"threats,omitempty"` } // Policy represents a policy document with metadata, contacts, scope, imports, implementation plan, risks, and adherence requirements. @@ -394,7 +585,7 @@ type Policy struct { Metadata Metadata `json:"metadata" yaml:"metadata"` - Contacts Contacts `json:"contacts" yaml:"contacts"` + Contacts RACI `json:"contacts" yaml:"contacts"` Scope Scope `json:"scope" yaml:"scope"` @@ -407,21 +598,6 @@ type Policy struct { Adherence Adherence `json:"adherence" yaml:"adherence"` } -// Contacts defines RACI roles for policy compliance and notification. -type Contacts struct { - // responsible is the person or group responsible for implementing controls for technical requirements - Responsible []Contact `json:"responsible" yaml:"responsible"` - - // accountable is the person or group accountable for evaluating and enforcing the efficacy of technical controls - Accountable []Contact `json:"accountable" yaml:"accountable"` - - // consulted is an optional person or group who may be consulted for more information about the technical requirements - Consulted []Contact `json:"consulted,omitempty" yaml:"consulted,omitempty"` - - // informed is an optional person or group who must receive updates about compliance with this policy - Informed []Contact `json:"informed,omitempty" yaml:"informed,omitempty"` -} - // Scope defines what is included and excluded from policy applicability. type Scope struct { In Dimensions `json:"in" yaml:"in"` @@ -498,9 +674,6 @@ type AssessmentRequirementModifier struct { Recommendation string `json:"recommendation,omitempty" yaml:"recommendation,omitempty"` } -// ModType defines the type of modification to the assessment requirement. -type ModType string - // GuidanceImport defines how to import guidance documents with optional exclusions and constraints. type GuidanceImport struct { ReferenceId string `json:"reference-id" yaml:"reference-id"` @@ -532,19 +705,38 @@ type ImplementationDetails struct { // Risks defines mitigated and accepted risks addressed by this policy. type Risks struct { // Mitigated risks only need reference-id and risk-id (no justification required) - Mitigated []MultiEntryMapping `json:"mitigated,omitempty" yaml:"mitigated,omitempty"` + Mitigated []MitigatedRisk `json:"mitigated,omitempty" yaml:"mitigated,omitempty"` // Accepted risks require rationale (justification) and may include scope. Controls addressing these risks are implicitly identified through threat mappings. Accepted []AcceptedRisk `json:"accepted,omitempty" yaml:"accepted,omitempty"` } -// RiskMapping maps a risk to a reference and optionally includes scope and justification. +// MitigatedRisk represents a risk addressed by the policy +type MitigatedRisk struct { + // id allows this mitigated risk entry to be referenced by accepted risks + Id string `json:"id" yaml:"id"` + + // risk references the risk being mitigated + Risk EntryMapping `json:"risk" yaml:"risk"` +} + +// AcceptedRisk documents a risk the organization has chosen to accept, +// optionally linking it to a mitigated risk when the acceptance covers +// residual risk after partial mitigation. type AcceptedRisk struct { + // id allows this accepted risk entry to be referenced + Id string `json:"id" yaml:"id"` + + // target-id optionally links this acceptance to a mitigated risk entry + Target_id string `json:"target-id,omitempty" yaml:"target-id,omitempty"` + + // risk references the risk being accepted Risk EntryMapping `json:"risk" yaml:"risk"` - // Scope and justification are only required for accepted risks (e.g., risk is accepted for TLP:Green and TLP:Clear because they contain non-sensitive data) + // scope defines where the risk acceptance applies Scope Scope `json:"scope,omitempty" yaml:"scope,omitempty"` + // justification explains why the risk is accepted Justification string `json:"justification,omitempty" yaml:"justification,omitempty"` } @@ -561,7 +753,7 @@ type Adherence struct { // AcceptedMethod defines a method for evaluation or enforcement. type AcceptedMethod struct { - Type string `json:"type" yaml:"type"` + Type MethodType `json:"type" yaml:"type"` Description string `json:"description,omitempty" yaml:"description,omitempty"` @@ -594,65 +786,91 @@ type Parameter struct { AcceptedValues []string `json:"accepted-values,omitempty" yaml:"accepted-values,omitempty"` } -type MethodType string +// ThreatCatalog describes a set of topically-associated threats +type ThreatCatalog struct { + // title describes the purpose of this catalog at a glance + Title string `json:"title" yaml:"title"` -// EvaluationLog contains the results of evaluating a set of Layer 2 controls. -type EvaluationLog struct { - Evaluations []*ControlEvaluation `json:"evaluations" yaml:"evaluations"` + // metadata provides detailed data about this catalog + Metadata Metadata `json:"metadata" yaml:"metadata"` + + // extends references threat catalogs that this catalog builds upon + Extends []ArtifactMapping `json:"extends,omitempty" yaml:"extends,omitempty"` + + // threats is a list of threats defined by this catalog + Threats []Threat `json:"threats,omitempty" yaml:"threats,omitempty"` + + // capabilities is a list of capabilities that make up the system being assessed + Capabilities []Capability `json:"capabilities,omitempty" yaml:"capabilities,omitempty"` - Metadata Metadata `json:"metadata,omitempty" yaml:"metadata,omitempty"` + // imports contains threats and capabilities from other sources which are included as part of this document + Imports ThreatCatalogImports `json:"imports,omitempty" yaml:"imports,omitempty"` } -// ControlEvaluation contains the results of evaluating a single Layer 5 control. -type ControlEvaluation struct { - Name string `json:"name" yaml:"name"` +// Threat describes a specifically-scoped opportunity for a negative impact to the organization +type Threat struct { + // id allows this entry to be referenced by other elements + Id string `json:"id" yaml:"id"` - Result Result `json:"result" yaml:"result"` + // title describes this threat at a glance + Title string `json:"title" yaml:"title"` - Message string `json:"message" yaml:"message"` + // description provides a detailed explanation of an opportunity for negative impact + Description string `json:"description" yaml:"description"` - Control EntryMapping `json:"control" yaml:"control"` + // capabilities documents the relationship between this threat and a system capability + Capabilities []MultiEntryMapping `json:"capabilities" yaml:"capabilities"` - // Enforce that control reference and the assessments' references match - // This formulation uses the control's reference if the assessment doesn't include a reference - AssessmentLogs []*AssessmentLog `json:"assessment-logs" yaml:"assessment-logs"` + // vectors documents the relationship between this threat and one or more vectors + Vectors []MultiEntryMapping `json:"vectors,omitempty" yaml:"vectors,omitempty"` + + // actors describes the relevant internal or external threat actors + Actors []Actor `json:"actors,omitempty" yaml:"actors,omitempty"` } -// AssessmentLog contains the results of executing a single assessment procedure for a control requirement. -type AssessmentLog struct { - // Requirement should map to the assessment requirement for this assessment. - Requirement EntryMapping `json:"requirement" yaml:"requirement"` +// Capability describes a system capability such as a feature, component or object. +type Capability struct { + // id allows this entry to be referenced by other elements + Id string `json:"id" yaml:"id"` - // Plan maps to the policy assessment plan being executed. - Plan *EntryMapping `json:"plan,omitempty" yaml:"plan,omitempty"` + // title describes this capability at a glance + Title string `json:"title" yaml:"title"` - // Description provides a summary of the assessment procedure. + // description provides a detailed overview of this capability Description string `json:"description" yaml:"description"` +} - // Result is the overall outcome of the assessment procedure, matching the result of the last step that was run. - Result Result `json:"result" yaml:"result"` +// ThreatCatalogImports defines imported entries for a threat catalog +type ThreatCatalogImports struct { + // threats is a list of threats from another source + Threats []MultiEntryMapping `json:"threats,omitempty" yaml:"threats,omitempty"` - // Message provides additional context about the assessment result. - Message string `json:"message" yaml:"message"` + // capabilities is a list of capabilities from another source + Capabilities []MultiEntryMapping `json:"capabilities,omitempty" yaml:"capabilities,omitempty"` +} - // Applicability is elevated from the Layer 2 Assessment Requirement to aid in execution and reporting. - Applicability []string `json:"applicability" yaml:"applicability"` +type VectorCatalog struct { + // title describes the contents of this catalog + Title string `json:"title" yaml:"title"` - // Steps are sequential actions taken as part of the assessment, which may halt the assessment if a failure occurs. - Steps []AssessmentStep `json:"steps" yaml:"steps"` + // metadata provides detailed data about this catalog + Metadata Metadata `json:"metadata" yaml:"metadata"` - // Steps-executed is the number of steps that were executed as part of the assessment. - StepsExecuted int64 `json:"steps-executed,omitempty" yaml:"steps-executed,omitempty"` + // vectors is a list of attack vectors documented in this catalog + Vectors []Vector `json:"vectors,omitempty" yaml:"vectors,omitempty"` +} - // Start is the timestamp when the assessment began. - Start Datetime `json:"start" yaml:"start"` +// A Vector represents a method, pathway, or technique through which a threat may be realized or an attack may be carried out. +type Vector struct { + // id allows this vector to be referenced by other elements + Id string `json:"id" yaml:"id"` - // End is the timestamp when the assessment concluded. - End Datetime `json:"end,omitempty" yaml:"end,omitempty"` + // title describes the vector + Title string `json:"title" yaml:"title"` - // Recommendation provides guidance on how to address a failed assessment. - Recommendation string `json:"recommendation,omitempty" yaml:"recommendation,omitempty"` + // description explains how the attack vector works + Description string `json:"description" yaml:"description"` - // ConfidenceLevel indicates the evaluator's confidence level in this specific assessment result. - ConfidenceLevel ConfidenceLevel `json:"confidence-level,omitempty" yaml:"confidence-level,omitempty"` + // applicability specifies the contexts in which this vector can manifest + Applicability []string `json:"applicability,omitempty" yaml:"applicability,omitempty"` } diff --git a/vendor/github.com/gemaraproj/go-gemara/loaders.go b/vendor/github.com/gemaraproj/go-gemara/loaders.go index efe26e6d..318745b1 100644 --- a/vendor/github.com/gemaraproj/go-gemara/loaders.go +++ b/vendor/github.com/gemaraproj/go-gemara/loaders.go @@ -83,7 +83,7 @@ func (c *ControlCatalog) LoadFiles(sourcePaths []string) error { } c.Families = append(c.Families, catalog.Families...) c.Controls = append(c.Controls, catalog.Controls...) - c.ImportedControls = append(c.ImportedControls, catalog.ImportedControls...) + c.Imports.Controls = append(c.Imports.Controls, catalog.Imports.Controls...) } return nil } diff --git a/vendor/github.com/gemaraproj/go-gemara/result.go b/vendor/github.com/gemaraproj/go-gemara/result.go deleted file mode 100644 index b8f8b3b4..00000000 --- a/vendor/github.com/gemaraproj/go-gemara/result.go +++ /dev/null @@ -1,67 +0,0 @@ -package gemara - -import "encoding/json" - -// Result is an enum representing the result of a control evaluation -// This is designed to restrict the possible result values to a set of known states -type Result int - -const ( - NotRun Result = iota - Passed - Failed - NeedsReview - NotApplicable - Unknown -) - -var toString = map[Result]string{ - NotRun: "Not Run", - Passed: "Passed", - Failed: "Failed", - NeedsReview: "Needs Review", - NotApplicable: "Not Applicable", - Unknown: "Unknown", -} - -func (r Result) String() string { - return toString[r] -} - -// MarshalYAML ensures that Result is serialized as a string in YAML -func (r Result) MarshalYAML() (interface{}, error) { - return r.String(), nil -} - -// MarshalJSON ensures that Result is serialized as a string in JSON -func (r Result) MarshalJSON() ([]byte, error) { - return json.Marshal(r.String()) -} - -// UpdateAggregateResult compares the current result with the new result and returns the most severe of the two. -func UpdateAggregateResult(previous Result, new Result) Result { - if new == NotRun { - // Not Run should not overwrite anything - // Failed should not be overwritten by anything - // Failed should overwrite anything - return previous - } - - if previous == Failed || new == Failed { - // Failed should not be overwritten by anything - // Failed should overwrite anything - return Failed - } - - if previous == Unknown || new == Unknown { - // If the current or past result is Unknown, it should not be overwritten by NeedsReview or Passed. - return Unknown - } - - if previous == NeedsReview || new == NeedsReview { - // NeedsReview should not be overwritten by Passed - // NeedsReview should overwrite Passed - return NeedsReview - } - return Passed -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 81a21515..430f5b18 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -53,8 +53,8 @@ github.com/erikgeiser/coninput # github.com/fatih/color v1.18.0 ## explicit; go 1.17 github.com/fatih/color -# github.com/gemaraproj/go-gemara v0.0.1 -## explicit; go 1.23.0 +# github.com/gemaraproj/go-gemara v0.0.2 +## explicit; go 1.24.0 github.com/gemaraproj/go-gemara github.com/gemaraproj/go-gemara/gemaraconv github.com/gemaraproj/go-gemara/internal/loaders