Skip to content

Commit

Permalink
Finished YAML validation pre-commit hook
Browse files Browse the repository at this point in the history
- Streamlined the YAML validation process by consolidating it into a shared function.
- Improved error messaging for enhanced clarity.
- Established a new function, loadSchema, to facilitate schema loading and unmarshalling from a YAML file.
- Enhanced ValidateYAML to accommodate schema path input and extended support for directory-wide YAML file validation.
- Revised the validateAllYAML function to furnish comprehensive error messages and enhanced logging.
- Elevated error handling for YAML validation by providing informative error messages.
- Augmented the inspectAndValidate function to adeptly manage nested SubTTPSteps and validate referenced files.
- Implemented custom validation to ascertain the presence of the "name" property when "ttp" is declared in a step.

This commit amplifies the effectiveness of YAML file validation, ensuring strict adherence to the schema.
Introduces a pre-commit hook mechanism to preemptively thwart the commitment of non-conforming YAML files.
  • Loading branch information
l50 committed Sep 7, 2023
1 parent 8740ef2 commit e519eea
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 209 deletions.
36 changes: 21 additions & 15 deletions .hooks/validate-yaml.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#!/bin/bash
set -ex
# This script is a pre-commit hook that checks if the mage command is
# installed and if not, prompts the user to install it. If mage is
# installed, the script changes to the repository root and runs the
# `mage validateyaml` command for each staged YAML file. This command
# validates all committed YAML files against a predefined schema. If any
# validation fails, the commit is stopped and an error message is shown.

set -e

# Change to the repository root
cd "$(git rev-parse --show-toplevel)"
Expand All @@ -20,24 +27,23 @@ fi
# Get the list of staged files ending with .yaml
staged_files=$(git diff --cached --name-only --diff-filter=AM | grep '\.yaml$')

# Variable to track whether validation failed
validation_failed=false
if [[ -z "$staged_files" ]]; then
echo "No YAML files to validate."
exit 0
fi

# Iterate over each staged file and validate it
for file in $staged_files; do
"${mage_bin}" validateallyamlfiles docs/ttpforge-spec.yaml "$file"
# Run the mage validateyaml command for the staged YAML file
"${mage_bin}" validateyaml docs/ttpforge-spec.yaml "$file"

# Capture the exit code of the last validation
exit_code=$?
# Catch the exit code of the last command
exit_status=$?

# If the exit code is not zero, set the flag to true
if [ $exit_code -ne 0 ]; then
validation_failed=true
# If the exit code is not zero (i.e., the command failed),
# then stop the commit and show an error message
if [ $exit_status -ne 0 ]; then
echo "Failed to validate YAML file '$file' against the schema."
exit 1
fi
done

# If any validation failed, exit with an error code
if [ "$validation_failed" = true ]; then
echo "Validation failed for one or more YAML files."
exit 1
fi
265 changes: 117 additions & 148 deletions docs/ttpforge-spec.yaml
Original file line number Diff line number Diff line change
@@ -1,161 +1,130 @@
---
TTP:
type: object
properties:
name:
type: string
description:
type: string
required: true
mitre:
$ref: "#/definitions/Mitre"
env:
type: object
additionalProperties:
type: string
steps:
type: array
items:
type: object
oneOf:
- $ref: "#/definitions/FileStep"
- $ref: "#/definitions/BasicStep"
- $ref: "#/definitions/SubTTPStep"
- $ref: "#/definitions/EditStep"
args:
type: array
items:
$ref: "#/definitions/Spec"
definitions:
TTP:
type: object
properties:
name:
type: string
description:
type: string
mitre:
$ref: "#/definitions/Mitre"
steps:
type: array
items:
oneOf:
- $ref: "#/definitions/SubTTPStep"
- $ref: "#/definitions/BasicStep"
- $ref: "#/definitions/EditStep"
args:
type: array
items:
$ref: "#/definitions/Spec"
required:
- name
- description
- steps

Act:
type: object
properties:
if:
type: string
env:
type: object
additionalProperties:
type: string
name:
type: string
required: true
outputs:
type: object
additionalProperties:
$ref: "#/definitions/Spec"
Mitre:
type: object
properties:
tactics:
type: array
items:
type: string
techniques:
type: array
items:
type: string
subtechniques:
type: array
items:
type: string

Mitre:
type: object
properties:
tactics:
type: array
items:
type: string
techniques:
type: array
items:
BasicStep:
type: object
properties:
name:
type: string
subtechniques:
type: array
items:
inline:
type: string
cleanup:
$ref: "#/definitions/CleanupAct"
args:
type: array
items:
type: string
required:
- name
- inline

FileStep:
type: object
properties:
act:
$ref: "#/definitions/Act"
file:
type: string
executor:
type: string
cleanup:
$ref: "#/definitions/CleanupAct"
args:
type: array
items:
CleanupAct:
type: object
properties:
inline:
type: string
required:
- inline

BasicStep:
type: object
properties:
act:
$ref: "#/definitions/Act"
executor:
type: string
inline:
type: string
args:
type: array
items:
type: string
cleanup:
type: string

SubTTPStep:
type: object
properties:
act:
$ref: "#/definitions/Act"
ttp:
type: string
args:
type: object
additionalProperties:
SubTTPStep:
type: object
properties:
name:
type: string
ttp:
type: string
args:
type: object
additionalProperties:
type: string
required:
- name
- ttp

Edit:
type: object
properties:
old:
type: string
new:
type: string
regexp:
type: boolean

EditStep:
type: object
properties:
act:
$ref: "#/definitions/Act"
edit_file:
type: string
edits:
type: array
items:
$ref: "#/definitions/Edit"
backup_file:
type: string

CleanupAct:
type: object
properties:
if:
type: string
env:
type: object
additionalProperties:
type: string
name:
type: string
required: true
outputs:
type: object
additionalProperties:
EditStep:
type: object
properties:
name:
type: string
edit_file:
type: string
backup_file:
type: string
edits:
type: array
items:
$ref: "#/definitions/Spec"
$ref: "#/definitions/Edit"
required:
- name
- edit_file
- backup_file
- edits

Spec:
type: object
properties:
name:
type: string
required: true
type:
type: string
default:
type: string
description:
type: string
Edit:
type: object
properties:
old:
type: string
new:
type: string
regexp:
type: string
required:
- old
- new
- regexp

Spec:
type: object
properties:
name:
type: string
type:
type: string
default:
type: string
description:
type: string
required:
- name
- type
10 changes: 3 additions & 7 deletions magefiles/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ go 1.21
toolchain go1.21.1

require (
github.com/facebookincubator/ttpforge v1.0.6
github.com/go-playground/validator/v10 v10.15.3
github.com/l50/goutils/v2 v2.1.0
github.com/spf13/afero v1.9.5
github.com/xeipuuv/gojsonschema v1.2.0
gopkg.in/yaml.v3 v3.0.1
)

Expand Down Expand Up @@ -40,13 +40,9 @@ require (
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/sergi/go-diff v1.3.1 // indirect
github.com/skeema/knownhosts v1.2.0 // indirect
github.com/tidwall/gjson v1.16.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.24.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect
Expand Down
Loading

0 comments on commit e519eea

Please sign in to comment.