Compare commits
No commits in common. "main" and "cloudtrail-0.2.5" have entirely different histories.
main
...
cloudtrail
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -8
|
||||
BreakBeforeBraces: Allman
|
||||
BreakConstructorInitializers: AfterColon
|
||||
ColumnLimit: 80
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
DerivePointerAlignment: true
|
||||
IndentWidth: 4
|
||||
SortIncludes: Never
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
SpaceBeforeParens: Never
|
||||
UseTab: Never
|
|
@ -1,6 +1,6 @@
|
|||
<!-- Thanks for sending a pull request! Here are some tips for you:
|
||||
|
||||
1. If this is your first time, please read our contributor guidelines in the [CONTRIBUTING.md](https://github.com/falcosecurity/.github/blob/main/CONTRIBUTING.md) file and learn how to compile Falco from source [here](https://falco.org/docs/source).
|
||||
1. If this is your first time, please read our contributor guidelines in the [CONTRIBUTING.md](https://github.com/falcosecurity/.github/blob/master/CONTRIBUTING.md) file and learn how to compile Falco from source [here](https://falco.org/docs/source).
|
||||
2. Please label this pull request according to what type of issue you are addressing.
|
||||
3. Please add a release note!
|
||||
4. If the PR is unfinished while opening it specify a wip in the title before the actual title, for example, "wip: my awesome feature"
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
RULES_DIR=$1
|
||||
CONFIG_FILE=$2
|
||||
PLUGIN_NAME=$3
|
||||
RESULT_FILE=$4
|
||||
CHECKER_TOOL=$5
|
||||
FALCO_DOCKER_IMAGE=$6
|
||||
LATEST_TAG=$7
|
||||
|
||||
set -e pipefail
|
||||
|
||||
rm -f $RESULT_FILE
|
||||
touch $RESULT_FILE
|
||||
|
||||
extra_flags=""
|
||||
loaded_plugins="$(cat $CONFIG_FILE | grep 'library_path: ' | cut -d ':' -f 2 | xargs)"
|
||||
for plugin_lib in $loaded_plugins; do
|
||||
extra_flags="${extra_flags} -f /usr/share/falco/plugins/${plugin_lib}"
|
||||
done
|
||||
|
||||
cur_branch=`git rev-parse HEAD`
|
||||
echo Current branch is \"$cur_branch\"
|
||||
echo Checking version for rules file in dir \"$RULES_DIR\"...
|
||||
# Get the rules files and save them.
|
||||
# We sort the rules files but first we remove the file extension.
|
||||
rules_files=$(ls ${RULES_DIR}/* | while read -r line; do echo "${line%.yaml}"; done | sort)
|
||||
# Add the extension to the files.
|
||||
# Append the .yaml extension back to the sorted strings
|
||||
rules_files=$(echo "${rules_files}" | sed 's/$/.yaml/')
|
||||
echo Rule files found: ${rules_files}
|
||||
|
||||
# We save the current rules files before going back to the previous
|
||||
# version.
|
||||
prefix="tmp-"
|
||||
for rules_file in ${rules_files}; do
|
||||
new_file="${prefix}$(basename "$rules_file")"
|
||||
echo "Copying rules file ${rules_file} to temporary file ${new_file}"
|
||||
cp "$rules_file" "$new_file"
|
||||
tmp_rules+=" $new_file"
|
||||
done
|
||||
|
||||
git checkout tags/$LATEST_TAG
|
||||
chmod +x $CHECKER_TOOL
|
||||
$CHECKER_TOOL \
|
||||
compare \
|
||||
--falco-image=$FALCO_DOCKER_IMAGE \
|
||||
-c $CONFIG_FILE \
|
||||
-l ${rules_files} \
|
||||
-r ${tmp_rules} \
|
||||
${extra_flags} \
|
||||
1>tmp_res.txt
|
||||
git switch --detach $cur_branch
|
||||
|
||||
echo '##' $(basename $RULES_DIR) >> $RESULT_FILE
|
||||
echo Comparing \`$cur_branch\` with latest tag \`$LATEST_TAG\` >> $RESULT_FILE
|
||||
echo "" >> $RESULT_FILE
|
||||
if [ -s tmp_res.txt ]
|
||||
then
|
||||
cat tmp_res.txt >> $RESULT_FILE
|
||||
else
|
||||
echo "No changes detected" >> $RESULT_FILE
|
||||
fi
|
||||
echo "" >> $RESULT_FILE
|
||||
|
||||
rm -f ${tmp_rules}
|
||||
rm -f tmp_res.txt
|
|
@ -1,35 +0,0 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gomod
|
||||
directories:
|
||||
- ./build/*
|
||||
- ./plugins/*
|
||||
- ./shared/go/*/*
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
groups:
|
||||
gomod:
|
||||
update-types:
|
||||
- "patch"
|
||||
- package-ecosystem: cargo
|
||||
directories:
|
||||
- /plugins/*
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
groups:
|
||||
cargo:
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
groups:
|
||||
actions:
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
|
@ -1,77 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# Plugins for which we need to check if there exist as alternative plugin.
|
||||
# If so, then we set them as a dependency. This is a must for rulesfiles
|
||||
# that have multiple plugins that satisfy their requirements and the plugin we are
|
||||
# checking is an alternative.
|
||||
# It accepts a single value or coma separated values.
|
||||
PLUGINS=$1
|
||||
|
||||
filtered_entries=()
|
||||
|
||||
# Extract plugins requirement from all files and save in a local file.
|
||||
# Combine the sections from multiple files and save the output to file.
|
||||
yq eval-all --no-doc '.[].required_plugin_versions | select(. != null and . != "")' ${@:2} > combined_requirements.yaml
|
||||
# Remove duplicates from the top level.
|
||||
yq eval-all --inplace 'unique_by(.name)' combined_requirements.yaml
|
||||
|
||||
#echo $(cat combined_requirements.yaml)
|
||||
|
||||
for YAML_FILE in "combined_requirements.yaml"; do
|
||||
#echo "Processing file $YAML_FILE"
|
||||
# Get the length of the entries list
|
||||
length=$(yq eval '. | length' "$YAML_FILE")
|
||||
# Iterate over each index in the entries list
|
||||
for ((i = 0; i < length; i++)); do
|
||||
# Access the entry by index using yq
|
||||
entry=$(yq eval '.['"$i"']' "$YAML_FILE")
|
||||
|
||||
# Extract name and version from the entry
|
||||
name=$(echo "$entry" | yq eval '.name' -)
|
||||
version=$(echo "$entry" | yq eval '.version' -)
|
||||
# If a plugin we are considering exists as an alternative of another one, then we just skip.
|
||||
# This case could happen when we are processing multiple files and one of them overrides the
|
||||
# plugin since it has some specific rules for that plugin.
|
||||
to_be_skipped=false
|
||||
for alternative in $(yq eval '.[].alternatives[].name' combined_requirements.yaml);do
|
||||
if [[ "$alternative" == "$name" ]]; then
|
||||
to_be_skipped=true
|
||||
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$to_be_skipped" = true ];then
|
||||
#echo "skipping plugin ${name} because already an alternative"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if alternatives exist
|
||||
alternatives=$(echo "$entry" | yq eval '.alternatives[]?')
|
||||
if [ -n "$alternatives" ]; then
|
||||
is_alternative=false
|
||||
# Get the length of the alternatives list
|
||||
alt_length=$(echo "$entry" | yq eval '.alternatives | length' -)
|
||||
# Iterate over each alternative
|
||||
for ((j = 0; j < alt_length; j++)); do
|
||||
alt_entry=$(echo "$entry" | yq eval '.alternatives['"$j"']?' -)
|
||||
alt_name=$(echo "$alt_entry" | yq eval '.name' -)
|
||||
alt_version=$(echo "$alt_entry" | yq eval '.version' -)
|
||||
# If our plugin is set as an alternative then we use it as a dependency.
|
||||
if [[ " ${PLUGINS//,/ } " =~ " $alt_name " ]]; then
|
||||
#echo "Preferring alternative plugin ${alt_name} over ${name}"
|
||||
is_alternative=true
|
||||
name=$alt_name
|
||||
version=$alt_version
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
filtered_entries+=("$name:$version")
|
||||
done
|
||||
done
|
||||
|
||||
# Output the filtered entries
|
||||
printf "%s\n" "${filtered_entries[@]}"
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
PLUGIN=$1
|
||||
|
||||
set +e pipefail
|
||||
echo Searching tag with prefix prefix \"${PLUGIN}-\"...
|
||||
git fetch --tags origin
|
||||
latest_tag=`git describe --match="${PLUGIN}-[0-9]*" --match="plugins/${PLUGIN}/v*" --abbrev=0 --tags`
|
||||
set -e pipefail
|
||||
|
||||
latest_ver="0.0.0"
|
||||
if [ -z "$latest_tag" ]
|
||||
then
|
||||
echo Not previous tag has been found
|
||||
else
|
||||
echo Most recent tag found is \"$latest_tag\"
|
||||
if [[ "${latest_tag}" == "plugins/${PLUGIN}"* ]]; then
|
||||
latest_ver="${latest_tag##*/v}"
|
||||
else
|
||||
latest_ver="${latest_tag##*-}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo Setting plugin version for "${PLUGIN}" to $latest_ver
|
||||
echo "version=$latest_ver" >> $GITHUB_OUTPUT
|
||||
echo "ref=${latest_tag}" >> $GITHUB_OUTPUT
|
|
@ -1,39 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
PLUGIN=$1
|
||||
|
||||
# set expected paths for plugins' config and rules files
|
||||
rules_dir="$GITHUB_WORKSPACE/plugins/${PLUGIN}/rules"
|
||||
config_file="$GITHUB_WORKSPACE/plugins/${PLUGIN}/falco.yaml"
|
||||
|
||||
# set paths into step outputs
|
||||
echo "rules_dir=${rules_dir}" >> "$GITHUB_OUTPUT"
|
||||
echo "config_file=${config_file}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# craft a default falco.yaml if no custom one is available
|
||||
if [ ! -f "$config_file" ]; then
|
||||
# we assume that the current plugin is always a dependency
|
||||
deps="$PLUGIN"
|
||||
|
||||
# we collect all plugin dependencies across all plugin rulesets
|
||||
# todo(jasondellaluce): find a way to avoid ignoring alternatives
|
||||
if [ -d "$rules_dir" ]; then
|
||||
rules_files=$(ls $rules_dir/*)
|
||||
echo Extracting plugin dependencies from rules file "${rules_files}"...
|
||||
rules_deps=$($GITHUB_WORKSPACE/.github/extract-plugins-deps-from-rulesfile.sh $PLUGIN $rules_files)
|
||||
echo "${rules_deps}"
|
||||
fi
|
||||
|
||||
mkdir -p $(echo $config_file | sed 's:[^/]*$::')
|
||||
touch $config_file
|
||||
echo "plugins:" >> $config_file
|
||||
for dep in $rules_deps; do
|
||||
dep=$(echo $dep | tr -d '"' | cut -d ':' -f 1)
|
||||
echo " - name: ${dep}" >> $config_file
|
||||
echo " library_path: lib${dep}.so" >> $config_file
|
||||
done
|
||||
fi
|
||||
|
||||
echo Using config file "${config_file}"
|
||||
cat ${config_file}
|
||||
echo ""
|
|
@ -1,22 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
falco_image=$1
|
||||
checker_tool=$2
|
||||
config_file=$3
|
||||
rules_files=$4
|
||||
|
||||
# craft rules validation command
|
||||
validation_flags=""
|
||||
for rules_file in $rules_files; do
|
||||
validation_flags="${validation_flags} -r ${rules_file}"
|
||||
done
|
||||
|
||||
# append plugin files to validation command
|
||||
configured_plugins="$(cat $config_file | grep 'library_path: ' | cut -d ':' -f 2 | xargs)"
|
||||
for plugin_lib in $configured_plugins; do
|
||||
validation_flags="${validation_flags} -f /usr/share/falco/plugins/${plugin_lib}"
|
||||
done
|
||||
|
||||
chmod +x $checker_tool
|
||||
echo $checker_tool validate -c $config_file $validation_flags
|
||||
$checker_tool validate --falco-image=$falco_image -c $config_file $validation_flags
|
|
@ -1,67 +0,0 @@
|
|||
name: Build Plugins PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
# Checks if any concurrent jobs under the same pull request or branch are being executed
|
||||
# NOTE: this will cancel every workflow that is being ran against a PR as group is just the github ref (without the workflow name)
|
||||
concurrency:
|
||||
group: ci-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-plugins:
|
||||
uses: ./.github/workflows/reusable_build_packages.yaml
|
||||
with:
|
||||
makecommand: make packages -j4
|
||||
suffix: ${{ github.event.number }}
|
||||
secrets: inherit
|
||||
|
||||
get-changed-plugins:
|
||||
uses: ./.github/workflows/reusable_get_changed_plugins.yaml
|
||||
|
||||
build-rules-tool:
|
||||
needs: [get-changed-plugins]
|
||||
if: needs.get-changed-plugins.outputs.changed-plugins != '[]' && needs.get-changed-plugins.outputs.changed-plugins != ''
|
||||
uses: ./.github/workflows/reusable_build_rules_tool.yaml
|
||||
with:
|
||||
output: rules-checker
|
||||
repository: falcosecurity/rules
|
||||
|
||||
validate-plugins:
|
||||
needs: [build-plugins, get-changed-plugins, build-rules-tool]
|
||||
if: needs.get-changed-plugins.outputs.changed-plugins != '[]' && needs.get-changed-plugins.outputs.changed-plugins != ''
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
plugin: ${{ fromJson(needs.get-changed-plugins.outputs.changed-plugins) }}
|
||||
uses: ./.github/workflows/reusable_validate_plugins.yaml
|
||||
with:
|
||||
plugin: ${{ matrix.plugin }}
|
||||
falcoctl-version: 0.11.0
|
||||
falco-image: falcosecurity/falco:0.40.0
|
||||
plugins-artifact: plugins-x86_64-${{ github.event.number }}.tar.gz
|
||||
rules-checker: ./rules-checker
|
||||
arch: x86_64
|
||||
|
||||
suggest-rules-version:
|
||||
needs: [build-plugins, get-changed-plugins, build-rules-tool]
|
||||
if: needs.get-changed-plugins.outputs.changed-plugins != '[]' && needs.get-changed-plugins.outputs.changed-plugins != ''
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
plugin: ${{ fromJson(needs.get-changed-plugins.outputs.changed-plugins) }}
|
||||
uses: ./.github/workflows/reusable_suggest_rules_version.yaml
|
||||
with:
|
||||
plugin: ${{ matrix.plugin }}
|
||||
falco-image: falcosecurity/falco:0.40.0
|
||||
plugins-artifact: plugins-x86_64-${{ github.event.number }}.tar.gz
|
||||
rules-checker: ./rules-checker
|
||||
arch: x86_64
|
||||
job-index: ${{ strategy.job-index }}
|
||||
|
||||
upload-pr-info:
|
||||
needs: [suggest-rules-version]
|
||||
if: needs.get-changed-plugins.outputs.changed-plugins != '[]' && needs.get-changed-plugins.outputs.changed-plugins != ''
|
||||
uses: ./.github/workflows/reusable_upload_pr_info.yaml
|
|
@ -9,23 +9,17 @@
|
|||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "Golang CodeQL"
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ main ]
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '28 11 * * 2'
|
||||
|
||||
# Checks if any concurrent jobs under the same pull request or branch are being executed
|
||||
# NOTE: this will cancel every workflow that is being ran against a PR as group is just the github ref (without the workflow name)
|
||||
concurrency:
|
||||
group: codeql-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
|
@ -37,23 +31,21 @@ jobs:
|
|||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp', 'go' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: 1.21
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: go
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
@ -62,7 +54,7 @@ jobs:
|
|||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
@ -76,4 +68,4 @@ jobs:
|
|||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
|
|
@ -1,171 +0,0 @@
|
|||
name: Build and test container plugin
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'plugins/container/**'
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'plugins/container/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-others:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ windows-latest, macos-latest ]
|
||||
include:
|
||||
- os: windows-latest
|
||||
artifact-name: 'libcontainer-win'
|
||||
artifact-path: 'plugins/container/container.dll'
|
||||
- os: macos-latest
|
||||
artifact-name: 'libcontainer-osx'
|
||||
artifact-path: 'plugins/container/libcontainer.dylib'
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version-file: plugins/container/go-worker/go.mod
|
||||
cache-dependency-path: plugins/container/go-worker/go.sum
|
||||
|
||||
- name: Build plugin library
|
||||
working-directory: plugins/container
|
||||
run: make
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: ${{ matrix.artifact-path }}
|
||||
|
||||
build-linux:
|
||||
name: build-linux-${{ matrix.arch }}
|
||||
runs-on: ${{ (matrix.arch == 'arm64' && 'ubuntu-22.04-arm') || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [ amd64, arm64 ]
|
||||
container: golang:1.23-bullseye
|
||||
steps:
|
||||
- name: Install plugin deps
|
||||
run: apt-get update && apt-get install -y --no-install-recommends zip unzip ninja-build
|
||||
|
||||
- name: Install updated cmake version ⛓️
|
||||
run: |
|
||||
curl -L -o /tmp/cmake.tar.gz https://github.com/Kitware/CMake/releases/download/v3.31.4/cmake-3.31.4-linux-$(uname -m).tar.gz
|
||||
gzip -d /tmp/cmake.tar.gz
|
||||
tar -xpf /tmp/cmake.tar --directory=/tmp
|
||||
cp -R /tmp/cmake-3.31.4-linux-$(uname -m)/* /usr
|
||||
rm -rf /tmp/cmake-3.31.4-linux-$(uname -m)
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Safe directory
|
||||
run: git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||
|
||||
- name: Build plugin library
|
||||
working-directory: plugins/container
|
||||
run: make
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: libcontainer-${{ matrix.arch }}
|
||||
path: 'plugins/container/libcontainer.so'
|
||||
|
||||
test:
|
||||
name: test-${{ matrix.arch }}
|
||||
needs: [build-linux]
|
||||
runs-on: ${{ (matrix.arch == 'arm64' && 'ubuntu-24.04-arm') || 'ubuntu-24.04' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [ amd64, arm64 ]
|
||||
steps:
|
||||
# libbtrfs: needed by podman package - build dep.
|
||||
- name: Install go test deps
|
||||
run: sudo apt-get install -y --no-install-recommends libbtrfs-dev
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version-file: plugins/container/go-worker/go.mod
|
||||
cache-dependency-path: plugins/container/go-worker/go.sum
|
||||
|
||||
- name: Build go-worker executable
|
||||
working-directory: plugins/container
|
||||
run: make -C go-worker exe
|
||||
|
||||
- name: Run tests
|
||||
working-directory: plugins/container
|
||||
run: |
|
||||
systemctl --user start podman
|
||||
make test
|
||||
|
||||
falco-tests:
|
||||
needs: [build-linux]
|
||||
name: falco-tests-${{ matrix.arch }}
|
||||
runs-on: ${{ (matrix.arch == 'arm64' && 'ubuntu-22.04-arm') || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [ amd64, arm64 ]
|
||||
container:
|
||||
image: falcosecurity/falco:master-debian
|
||||
steps:
|
||||
- name: Download library
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: libcontainer-${{ matrix.arch }}
|
||||
path: /usr/share/falco/plugins/
|
||||
|
||||
- name: Run falcosecurity/testing Falco tests
|
||||
uses: falcosecurity/testing@main
|
||||
with:
|
||||
test-falco: 'true'
|
||||
test-falcoctl: 'false'
|
||||
test-k8saudit: 'false'
|
||||
test-dummy: 'false'
|
||||
static: 'false'
|
||||
test-drivers: 'false'
|
||||
show-all: 'true'
|
||||
sudo: ''
|
||||
|
||||
libs-tests:
|
||||
needs: [build-linux]
|
||||
uses: falcosecurity/libs/.github/workflows/reusable_e2e_tests.yaml@master
|
||||
with:
|
||||
container_plugin_artifact_name: 'libcontainer-amd64'
|
||||
secrets: inherit
|
||||
|
||||
formatting-check:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Run clang-format style check
|
||||
uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 #v4.15.0
|
||||
with:
|
||||
clang-format-version: '18'
|
||||
check-path: plugins/container
|
||||
exclude-regex: 'plugin_config_schema.h'
|
|
@ -1,54 +0,0 @@
|
|||
# NOTE: This has read-write repo token and access to secrets, so this must
|
||||
# not run any untrusted code.
|
||||
# see: https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
|
||||
name: Comment on the pull request
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Build Plugins PR"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.workflow_run.event == 'pull_request'
|
||||
steps:
|
||||
- name: 'Download artifact'
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
with:
|
||||
script: |
|
||||
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: ${{github.event.workflow_run.id }},
|
||||
});
|
||||
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
|
||||
return artifact.name == "pr"
|
||||
})[0];
|
||||
var download = await github.rest.actions.downloadArtifact({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
artifact_id: matchArtifact.id,
|
||||
archive_format: 'zip',
|
||||
});
|
||||
var fs = require('fs');
|
||||
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
|
||||
|
||||
- name: 'Unpack artifact'
|
||||
run: unzip pr.zip
|
||||
|
||||
- name: 'Comment on PR'
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
var fs = require('fs');
|
||||
var issue_number = Number(fs.readFileSync('./NR'));
|
||||
var comment_body = fs.readFileSync('./COMMENT');
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue_number,
|
||||
body: comment_body.toString('utf8')
|
||||
});
|
|
@ -1,56 +0,0 @@
|
|||
name: Build dummy_c plugin
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'plugins/dummy_c/**'
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'plugins/dummy_c/**'
|
||||
workflow_dispatch:
|
||||
|
||||
# Checks if any concurrent jobs under the same pull request or branch are being executed
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: build
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout ⤵️
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install deps ⛓️
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt install -y --no-install-recommends build-essential
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
with:
|
||||
languages: cpp
|
||||
|
||||
- name: Build dummy_c plugin 🏗️
|
||||
run: |
|
||||
cd plugins/dummy_c
|
||||
make libdummy_c.so
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
|
||||
formatting-check:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Run clang-format style check
|
||||
uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 #v4.15.0
|
||||
with:
|
||||
clang-format-version: '14'
|
||||
check-path: plugins/dummy_c
|
|
@ -1,72 +0,0 @@
|
|||
name: Build K8smeta plugin
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'plugins/k8smeta/**'
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'plugins/k8smeta/**'
|
||||
workflow_dispatch:
|
||||
|
||||
# Checks if any concurrent jobs under the same pull request or branch are being executed
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
name: build-and-test
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout ⤵️
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: '1.21'
|
||||
check-latest: true
|
||||
|
||||
- name: Install deps ⛓️
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt install -y --no-install-recommends cmake build-essential autoconf libtool pkg-config
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
with:
|
||||
languages: cpp
|
||||
|
||||
- name: Build k8s meta plugin 🏗️
|
||||
run: |
|
||||
cd plugins/k8smeta
|
||||
mkdir build
|
||||
cd build && cmake -DCMAKE_BUILD_TYPE=Release ../
|
||||
make k8smeta -j6
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
|
||||
- name: Build and run tests 🏎️
|
||||
run: |
|
||||
cd plugins/k8smeta/build
|
||||
make build-server
|
||||
make build-tests
|
||||
make run-server &
|
||||
make run-tests
|
||||
|
||||
formatting-check:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Run clang-format style check
|
||||
uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 #v4.15.0
|
||||
with:
|
||||
clang-format-version: '14'
|
||||
check-path: plugins/k8smeta
|
|
@ -1,61 +0,0 @@
|
|||
name: Update Plugins-dev
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
# Checks if any concurrent jobs is already being executed for main and cancel it.
|
||||
concurrency:
|
||||
group: ci-main
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-plugins-dev:
|
||||
uses: falcosecurity/plugins/.github/workflows/reusable_build_packages.yaml@main
|
||||
with:
|
||||
makecommand: make packages -j4
|
||||
suffix: dev
|
||||
secrets: inherit
|
||||
|
||||
get-changed-plugins:
|
||||
uses: ./.github/workflows/reusable_get_changed_plugins.yaml
|
||||
|
||||
build-rules-tool:
|
||||
needs: [get-changed-plugins]
|
||||
if: needs.get-changed-plugins.outputs.changed-plugins != '[]' && needs.get-changed-plugins.outputs.changed-plugins != ''
|
||||
uses: ./.github/workflows/reusable_build_rules_tool.yaml
|
||||
with:
|
||||
output: rules-checker
|
||||
repository: falcosecurity/rules
|
||||
|
||||
validate-plugins:
|
||||
needs: [build-plugins-dev, get-changed-plugins, build-rules-tool]
|
||||
if: needs.get-changed-plugins.outputs.changed-plugins != '[]' && needs.get-changed-plugins.outputs.changed-plugins != ''
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
plugin: ${{ fromJson(needs.get-changed-plugins.outputs.changed-plugins) }}
|
||||
uses: ./.github/workflows/reusable_validate_plugins.yaml
|
||||
with:
|
||||
plugin: ${{ matrix.plugin }}
|
||||
falcoctl-version: 0.11.0
|
||||
falco-image: falcosecurity/falco:0.40.0
|
||||
plugins-artifact: plugins-x86_64-dev.tar.gz
|
||||
rules-checker: ./rules-checker
|
||||
arch: x86_64
|
||||
|
||||
publish-plugins-dev:
|
||||
needs: [build-plugins-dev, validate-plugins]
|
||||
uses: falcosecurity/plugins/.github/workflows/reusable_publish_packages.yaml@main
|
||||
with:
|
||||
suffix: dev
|
||||
secrets: inherit
|
||||
|
||||
publish-oci-artifacts-dev:
|
||||
needs: [ build-plugins-dev, validate-plugins ]
|
||||
uses: ./.github/workflows/reusable-publish-oci-artifacts.yaml
|
||||
with:
|
||||
dev-tag: main
|
||||
suffix: dev
|
||||
secrets: inherit
|
|
@ -1,43 +0,0 @@
|
|||
name: Check registry.yaml
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "registry.yaml"
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "registry.yaml"
|
||||
workflow_dispatch:
|
||||
|
||||
# Checks if any concurrent jobs under the same pull request or branch are being executed
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check-registry:
|
||||
name: check-registry
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout ⤵️
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: "1.21"
|
||||
check-latest: true
|
||||
|
||||
- name: Build registry artifact tool
|
||||
working-directory: build/registry
|
||||
run: make
|
||||
|
||||
# Formal validation only.
|
||||
# When a new plugin is added and not yet released,
|
||||
# its OCI repo has not been created yet, so we can't validate it.
|
||||
- name: Verify the correctness of registry.yaml
|
||||
working-directory: build/registry
|
||||
run: ./bin/registry check ../../registry.yaml
|
|
@ -1,70 +0,0 @@
|
|||
name: Release Plugins
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
# All tags
|
||||
- '**'
|
||||
|
||||
# Checks if any concurrent jobs is running for release CI and eventually cancel it.
|
||||
concurrency:
|
||||
group: ci-release-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
extract-info:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
package: ${{ steps.regex-match.outputs.group1 }}
|
||||
|
||||
steps:
|
||||
- name: Validate tag ℹ️
|
||||
uses: actions-ecosystem/action-regex-match@9e6c4fb3d5e898f505be7a1fb6e7b0a278f6665b # v2.0.2
|
||||
id: regex-match
|
||||
with:
|
||||
text: ${{ github.ref_name }}
|
||||
regex: '^plugins\/([a-z0-9_-]+)\/v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
|
||||
|
||||
- name: Fail on invalid tag
|
||||
if: steps.regex-match.outputs.match == ''
|
||||
run: exit 1
|
||||
|
||||
build-plugins:
|
||||
needs: extract-info
|
||||
uses: falcosecurity/plugins/.github/workflows/reusable_build_packages.yaml@main
|
||||
with:
|
||||
makecommand: make release/${{ needs.extract-info.outputs.package }} -j4
|
||||
suffix: stable
|
||||
secrets: inherit
|
||||
|
||||
build-rules-tool:
|
||||
needs: [extract-info]
|
||||
uses: ./.github/workflows/reusable_build_rules_tool.yaml
|
||||
with:
|
||||
output: rules-checker
|
||||
repository: falcosecurity/rules
|
||||
|
||||
validate-plugins:
|
||||
needs: [extract-info, build-plugins, build-rules-tool]
|
||||
uses: ./.github/workflows/reusable_validate_plugins.yaml
|
||||
with:
|
||||
plugin: ${{ needs.extract-info.outputs.package }}
|
||||
falcoctl-version: 0.11.0
|
||||
falco-image: falcosecurity/falco:0.40.0
|
||||
plugins-artifact: plugins-x86_64-stable.tar.gz
|
||||
rules-checker: ./rules-checker
|
||||
arch: x86_64
|
||||
|
||||
publish-plugins:
|
||||
needs: [build-plugins, validate-plugins]
|
||||
uses: falcosecurity/plugins/.github/workflows/reusable_publish_packages.yaml@main
|
||||
with:
|
||||
suffix: stable
|
||||
secrets: inherit
|
||||
|
||||
publish-oci-artifacts:
|
||||
needs: [ build-plugins, validate-plugins ]
|
||||
uses: ./.github/workflows/reusable-publish-oci-artifacts.yaml
|
||||
with:
|
||||
suffix: stable
|
||||
secrets: inherit
|
|
@ -1,98 +0,0 @@
|
|||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
dev-tag:
|
||||
description: The tag used for oci artifacts published from the main branch.
|
||||
required: false
|
||||
type: string
|
||||
suffix:
|
||||
description: Suffix for uploading packages (dev or stable)
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
publish-oci-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
matrix: ${{ steps.oci_build.outputs.REGISTRY_UPDATE_STATUS }}
|
||||
|
||||
steps:
|
||||
- name: Download x86_64 plugins
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: plugins-x86_64-${{ inputs.suffix }}.tar.gz
|
||||
path: /tmp/plugins-x86_64
|
||||
|
||||
- name: Download aarch64 plugins
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: plugins-aarch64-${{ inputs.suffix }}.tar.gz
|
||||
path: /tmp/plugins-aarch64
|
||||
|
||||
- name: Checkout Plugins
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: "^1.21"
|
||||
|
||||
- name: Build registry artifact tool
|
||||
working-directory: build/registry
|
||||
run: make
|
||||
|
||||
- name: Upload OCI artifacts to GitHub packages
|
||||
id: oci_build
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
REGISTRY_USER: ${{ github.repository_owner }}
|
||||
REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
REPO_GITHUB: https://github.com/${{ github.repository_owner }}/plugins.git
|
||||
working-directory: build/registry
|
||||
run: |
|
||||
REGISTRY_UPDATE_STATUS=$(./bin/registry update-oci-registry \
|
||||
../../registry.yaml \
|
||||
--plugins-amd64-path /tmp/plugins-x86_64 \
|
||||
--plugins-arm64-path /tmp/plugins-aarch64 \
|
||||
--rulesfiles-path /tmp/plugins-x86_64 \
|
||||
--dev-tag "${{ inputs.dev-tag }}"
|
||||
)
|
||||
echo "REGISTRY_UPDATE_STATUS=${REGISTRY_UPDATE_STATUS}" >> $GITHUB_OUTPUT
|
||||
|
||||
# Create signatures of the plugin artifacts as OCI artifacts
|
||||
sign-oci-artifacts:
|
||||
needs: [publish-oci-artifacts]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: ${{ needs.publish-oci-artifacts.outputs.matrix != '[]' }}
|
||||
strategy:
|
||||
matrix:
|
||||
value: ${{ fromJson(needs.publish-oci-artifacts.outputs.matrix) }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2
|
||||
|
||||
- run: cosign version
|
||||
|
||||
- name: Log into ghcr.io
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Sign the artifacts with GitHub OIDC Token
|
||||
run: cosign sign --yes ${{ matrix.value.repository.ref }}@${{ matrix.value.artifact.digest }}
|
|
@ -1,74 +0,0 @@
|
|||
# This is a reusable workflow used by main and release CI
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
makecommand:
|
||||
description: Command used for make
|
||||
required: true
|
||||
type: string
|
||||
suffix:
|
||||
description: Suffix for uploading packages (dev or stable)
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-packages:
|
||||
name: build-packages-${{ matrix.arch }}
|
||||
runs-on: ${{ (matrix.arch == 'aarch64' && 'ubuntu-22.04-arm') || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, aarch64]
|
||||
# Upgrading to a newer debian version would make the build process generate
|
||||
# binaries that require newer GLIBC version so we need to be based on bullseye for now
|
||||
container: golang:1.23-bullseye
|
||||
steps:
|
||||
- name: Install deps
|
||||
run: |
|
||||
apt update
|
||||
apt install -y --no-install-recommends awscli build-essential autoconf libelf-dev libtool autotools-dev \
|
||||
automake zip unzip ninja-build wget lsb-release software-properties-common gnupg
|
||||
|
||||
- name: Install updated clang version ⛓️
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod u+x llvm.sh
|
||||
./llvm.sh 19
|
||||
ln -s /usr/bin/clang-19 /usr/bin/clang
|
||||
|
||||
- name: Install updated cmake version ⛓️
|
||||
run: |
|
||||
curl -L -o /tmp/cmake.tar.gz https://github.com/Kitware/CMake/releases/download/v3.31.4/cmake-3.31.4-linux-$(uname -m).tar.gz
|
||||
gzip -d /tmp/cmake.tar.gz
|
||||
tar -xpf /tmp/cmake.tar --directory=/tmp
|
||||
cp -R /tmp/cmake-3.31.4-linux-$(uname -m)/* /usr
|
||||
rm -rf /tmp/cmake-3.31.4-linux-$(uname -m)
|
||||
|
||||
- name: Install Rust 🦀
|
||||
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # v1
|
||||
with:
|
||||
toolchain: "1.86.0"
|
||||
|
||||
- name: Install bpf-linker
|
||||
run: |
|
||||
cargo install bpf-linker@0.9.14
|
||||
|
||||
- name: Configure Rust cache
|
||||
uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 #v2
|
||||
|
||||
- name: Checkout Plugins ⤵️
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Safe directory
|
||||
run: git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||
|
||||
- name: Run build 🏗️
|
||||
run: ${{ inputs.makecommand }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: plugins-${{ matrix.arch }}-${{ inputs.suffix }}.tar.gz
|
||||
path: output/*.tar.gz
|
|
@ -1,43 +0,0 @@
|
|||
# This is a reusable workflow used by main and release CI
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
output:
|
||||
description: Name of the output binary
|
||||
required: false
|
||||
default: rules-check
|
||||
type: string
|
||||
repository:
|
||||
description: Falco rules repository
|
||||
required: false
|
||||
default: falcosecurity/rules
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-rules-checker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: "1.19.0"
|
||||
|
||||
- name: Checkout rules
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
repository: ${{ inputs.repository }}
|
||||
|
||||
- name: Build checker tool
|
||||
working-directory: build/checker
|
||||
run: go build -o ${{ inputs.output }}
|
||||
|
||||
- name: Test checker tool
|
||||
working-directory: build/checker
|
||||
run: go test ./... -cover
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: rules-tool.tar.gz
|
||||
path: build/checker/${{ inputs.output }}
|
||||
retention-days: 1
|
|
@ -1,46 +0,0 @@
|
|||
# This is a reusable workflow used by main CI
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
changed-plugins:
|
||||
description: "A json-encoded array with the names of plugins to be used by the CI"
|
||||
value: ${{ jobs.get-values.outputs.changed-plugins }}
|
||||
|
||||
jobs:
|
||||
get-values:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
changed-plugins: ${{ steps.set-changed-plugins.outputs.changed-plugins }}
|
||||
steps:
|
||||
- name: Checkout rules
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Get changed files
|
||||
id: changed-plugins
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: Ana06/get-changed-files@25f79e676e7ea1868813e21465014798211fad8c # v2.3.0
|
||||
with:
|
||||
format: space-delimited
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get changed plugins
|
||||
id: set-changed-plugins
|
||||
run: |
|
||||
# if we skip changed-plugins because we're not in a pull-request,
|
||||
# then we consider all the rules contained in the repo
|
||||
all_files="${{ steps.changed-plugins.outputs.all }}"
|
||||
values=""
|
||||
if [ -z "$all_files" ]; then
|
||||
values=$(ls plugins)
|
||||
else
|
||||
for changed_file in $all_files; do
|
||||
if [[ ${changed_file} =~ ^plugins/.* ]]; then
|
||||
plugindir=$(echo ${changed_file} | sed -e 's/^plugins//' | sed -E 's_(/[^/]+).*_\1_')
|
||||
pluginname="${plugindir:1}"
|
||||
if [[ ! $values =~ "$pluginname" ]]; then
|
||||
values="${values}$pluginname"$'\n'
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo "changed-plugins=$(echo "${values}" | jq -R -s -c 'split("\n")' | jq -c 'map(select(length > 0))')" >> $GITHUB_OUTPUT
|
|
@ -1,45 +0,0 @@
|
|||
# This is a reusable workflow used by main and release CI
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
suffix:
|
||||
description: Suffix for uploading packages (dev or stable)
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
|
||||
env:
|
||||
AWS_S3_BUCKET: falco-distribution
|
||||
AWS_S3_PREFIX: plugins
|
||||
AWS_S3_REGION: eu-west-1
|
||||
|
||||
jobs:
|
||||
publish-packages:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download x86_64 plugins
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: plugins-x86_64-${{ inputs.suffix }}.tar.gz
|
||||
path: /tmp/plugins-x86_64
|
||||
|
||||
- name: Download aarch64 plugins
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: plugins-aarch64-${{ inputs.suffix }}.tar.gz
|
||||
path: /tmp/plugins-aarch64
|
||||
|
||||
- name: Configure AWS credentials 🔧⚙️
|
||||
uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
|
||||
with:
|
||||
role-to-assume: "arn:aws:iam::292999226676:role/github_actions-plugins-s3"
|
||||
aws-region: ${{ env.AWS_S3_REGION }}
|
||||
|
||||
- name: Upload files to S3 ⬆️
|
||||
run: |
|
||||
for package in /tmp/plugins-*/*.tar.gz; do
|
||||
aws s3 cp --no-progress $package s3://${{ env.AWS_S3_BUCKET}}/${{ env.AWS_S3_PREFIX }}/${{ inputs.suffix }}/
|
||||
done
|
|
@ -1,122 +0,0 @@
|
|||
# This is a reusable workflow used by the PR CI
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
plugin:
|
||||
description: Name of the plugin that needs to be validated
|
||||
required: true
|
||||
type: string
|
||||
falco-image:
|
||||
description: Docker image of Falco to be used for validation
|
||||
required: true
|
||||
type: string
|
||||
plugins-artifact:
|
||||
description: Name of the plugin artifact containing the dev builds
|
||||
required: true
|
||||
type: string
|
||||
rules-checker:
|
||||
description: Path of the rules checker tool built from falcosecurity/rules
|
||||
required: true
|
||||
type: string
|
||||
arch:
|
||||
description: Architecture of the plugins artifacts (x86_64 or aarch64)
|
||||
required: true
|
||||
type: string
|
||||
job-index:
|
||||
description: If used in a matrix, the value of strategy.job-index
|
||||
required: false
|
||||
default: 0
|
||||
type: number
|
||||
|
||||
jobs:
|
||||
# note: we don't need anything else than x86_64 since we're validating rules
|
||||
check-version:
|
||||
if: github.event_name == 'pull_request' && inputs.arch == 'x86_64'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install system dependencies
|
||||
run: sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq && sudo chmod +x /usr/bin/yq
|
||||
|
||||
- name: Setup plugin config and rules
|
||||
id: get-config
|
||||
run: ./.github/setup-plugin-config-rules.sh ${{ inputs.plugin }}
|
||||
|
||||
- name: Get latest tag
|
||||
id: get-tag
|
||||
run: ./.github/get-latest-plugin-version.sh ${{ inputs.plugin }}
|
||||
|
||||
- name: Download rules tool
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: rules-tool.tar.gz
|
||||
|
||||
# note: here we're loading the locally-built plugins, whereas another
|
||||
# solution would be to pull them with falcoctl. The flaw with this
|
||||
# approach is that we load the same plugin for both the "old" and the
|
||||
# "new" rulesets. The issue would be that the job would fail whenever
|
||||
# the two rulesets depend on plugins with different majors.
|
||||
# todo(jasondellaluce): fix this corner case in the future
|
||||
- name: Download plugins
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: ${{ inputs.plugins-artifact }}
|
||||
path: /tmp/plugins-${{ inputs.arch }}
|
||||
|
||||
- name: Extract plugins
|
||||
run: |
|
||||
for archive in /tmp/plugins-*/*.tar.gz; do
|
||||
echo Extracting archive "$archive"...
|
||||
mkdir -p tmpdir && pushd tmpdir
|
||||
tar -xvf $archive
|
||||
sudo mkdir -p /usr/share/falco/plugins
|
||||
sudo cp -r *.so /usr/share/falco/plugins || true
|
||||
popd && rm -fr tmpdir
|
||||
done
|
||||
|
||||
- name: Compare changed files with previous versions
|
||||
id: compare
|
||||
if: steps.get-tag.outputs.version != '0.0.0'
|
||||
run: |
|
||||
rules_dir=${{ steps.get-config.outputs.rules_dir }}
|
||||
|
||||
if [ -d "$rules_dir" ]; then
|
||||
./.github/compare-rule-files.sh \
|
||||
"$rules_dir" \
|
||||
${{ steps.get-config.outputs.config_file }} \
|
||||
${{ inputs.plugin }} \
|
||||
rule_result.txt \
|
||||
${{ inputs.rules-checker }} \
|
||||
${{ inputs.falco-image }} \
|
||||
${{ steps.get-tag.outputs.ref }}
|
||||
|
||||
if [ -s rule_result.txt ]; then
|
||||
if [ ! -s result.txt ]; then
|
||||
touch result.txt
|
||||
fi
|
||||
cat rule_result.txt >> result.txt
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -s result.txt ]; then
|
||||
echo "comment_file=result.txt" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Save PR info
|
||||
if: steps.compare.outputs.comment_file != ''
|
||||
run: |
|
||||
mkdir -p ./pr
|
||||
cp ${{ steps.compare.outputs.comment_file }} ./pr/COMMENT-${{ inputs.job-index }}
|
||||
|
||||
- name: Upload PR info as artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
if: steps.compare.outputs.comment_file != ''
|
||||
with:
|
||||
name: pr-${{ inputs.job-index }}
|
||||
path: pr/
|
||||
retention-days: 1
|
|
@ -1,37 +0,0 @@
|
|||
# This is a reusable workflow used by the PR CI
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
upload-pr-info:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download PR infos
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
path: tmp-artifacts
|
||||
|
||||
- name: Save PR info
|
||||
run: |
|
||||
mkdir -p ./pr
|
||||
echo ${{ github.event.number }} > ./pr/NR
|
||||
touch ./pr/COMMENT
|
||||
echo "# Rules files suggestions" >> ./pr/COMMENT
|
||||
echo "" >> ./pr/COMMENT
|
||||
files=$(find ./tmp-artifacts/)
|
||||
for file in $files; do
|
||||
if [[ $file =~ "COMMENT" ]]; then
|
||||
cat $file >> ./pr/COMMENT
|
||||
fi
|
||||
done
|
||||
echo Uploading PR info...
|
||||
cat ./pr/COMMENT
|
||||
echo ""
|
||||
|
||||
- name: Upload PR info as artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: pr
|
||||
path: pr/
|
||||
retention-days: 1
|
|
@ -1,226 +0,0 @@
|
|||
# This is a reusable workflow used by main and release CI
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
plugin:
|
||||
description: Name of the plugin that needs to be validated
|
||||
required: true
|
||||
type: string
|
||||
falco-image:
|
||||
description: Docker image of Falco to be used for validation
|
||||
required: true
|
||||
type: string
|
||||
falcoctl-version:
|
||||
description: Version of falcoctl to be used for pulling artifacts
|
||||
required: true
|
||||
type: string
|
||||
plugins-artifact:
|
||||
description: Name of the plugin artifact containing the dev builds
|
||||
required: true
|
||||
type: string
|
||||
rules-checker:
|
||||
description: Path of the rules checker tool built from falcosecurity/rules
|
||||
required: true
|
||||
type: string
|
||||
arch:
|
||||
description: Architecture of the plugins artifacts (x86_64 or aarch64)
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
# todo(jasondellaluce): support aarch64 too
|
||||
validate-local:
|
||||
if: inputs.arch == 'x86_64'
|
||||
runs-on: ubuntu-latest
|
||||
container: golang:1.18
|
||||
env:
|
||||
GOFLAGS: "-buildvcs=false"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Install system dependencies
|
||||
run: wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq && chmod +x /usr/bin/yq
|
||||
|
||||
- name: Setup plugin config and rules
|
||||
id: get-config
|
||||
run: ./.github/setup-plugin-config-rules.sh ${{ inputs.plugin }}
|
||||
|
||||
- name: Download rules tool
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: rules-tool.tar.gz
|
||||
|
||||
- name: Download plugins
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: ${{ inputs.plugins-artifact }}
|
||||
path: /tmp/plugins-${{ inputs.arch }}
|
||||
|
||||
- name: Install plugin and rules
|
||||
run: |
|
||||
set -e pipefail
|
||||
|
||||
arch=${{ inputs.arch }}
|
||||
loaded_plugins="$(cat ${{ steps.get-config.outputs.config_file }} | grep '\- name: ' | cut -d ':' -f 2 | xargs)"
|
||||
|
||||
mkdir -p /etc/falco/falco
|
||||
mkdir -p /usr/share/falco/plugins
|
||||
|
||||
# avoids git exit status 128: detected dubious ownership in repository
|
||||
git config --global --add safe.directory $(pwd)
|
||||
|
||||
for plugin_name in $loaded_plugins; do
|
||||
echo Installing locally-built plugin "$plugin_name"...
|
||||
|
||||
# At release time we only build the released plugin, so it's possible
|
||||
# that validation requires a plugin that we haven't built locally.
|
||||
# in those cases, we build it on-the-fly perform validation with it.
|
||||
set +e pipefail
|
||||
packages=$(ls /tmp/plugins-${arch}/${plugin_name}-* || echo "")
|
||||
set -e pipefail
|
||||
if [ -z "$packages" ]; then
|
||||
echo Building plugin "$plugin_name" temporary packages...
|
||||
make package/$plugin_name -j4
|
||||
packages=$(ls $(pwd)/output/${plugin_name}-*)
|
||||
fi
|
||||
|
||||
for archive in $packages; do
|
||||
echo Extracting archive "$archive"...
|
||||
mkdir -p tmpdir && cd tmpdir
|
||||
tar -xvf $archive
|
||||
cp -r *.yaml /etc/falco/falco || true
|
||||
cp -r *.so /usr/share/falco/plugins || true
|
||||
cd .. && rm -fr tmpdir
|
||||
done
|
||||
done
|
||||
|
||||
- name: Validate plugin and rules
|
||||
run: |
|
||||
# craft an empty rules file if none is available.
|
||||
# this ensures that the plugin gets still loaded even if it has no rules.
|
||||
rules_files=""
|
||||
if [ ! -d "${{ steps.get-config.outputs.rules_dir }}" ]; then
|
||||
touch tmp_rules.yaml
|
||||
rules_files="./tmp_rules.yaml"
|
||||
else
|
||||
rules_files=$(ls ${{ steps.get-config.outputs.rules_dir }}/*)
|
||||
fi
|
||||
|
||||
./.github/validate-rules.sh \
|
||||
"${{ inputs.falco-image }}" \
|
||||
"${{ inputs.rules-checker }}" \
|
||||
"${{ steps.get-config.outputs.config_file }}" \
|
||||
"$rules_files"
|
||||
|
||||
# todo(jasondellaluce): support aarch64 too
|
||||
validate-falcoctl:
|
||||
if: inputs.arch == 'x86_64'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Install system dependencies
|
||||
run: sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq && sudo chmod +x /usr/bin/yq
|
||||
|
||||
- name: Setup plugin config and rules
|
||||
id: get-config
|
||||
run: ./.github/setup-plugin-config-rules.sh ${{ inputs.plugin }}
|
||||
|
||||
- name: Download plugins
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: ${{ inputs.plugins-artifact }}
|
||||
path: /tmp/plugins-${{ inputs.arch }}
|
||||
|
||||
- name: Download rules tool
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: rules-tool.tar.gz
|
||||
|
||||
- name: Download falcoctl
|
||||
run: |
|
||||
curl --fail -LS "https://github.com/falcosecurity/falcoctl/releases/download/v${{ inputs.falcoctl-version }}/falcoctl_${{ inputs.falcoctl-version }}_linux_${{ inputs.arch == 'x86_64' && 'amd64' || 'arm64' }}.tar.gz" | tar -xz
|
||||
sudo install -o root -g root -m 0755 falcoctl /usr/local/bin/falcoctl
|
||||
|
||||
# note(jsondellaluce): exploring the set of all dependencies including their
|
||||
# alternatives and all the possible combinations of different versions would
|
||||
# result in a combinatorial explosion. As such, we take the simple route
|
||||
# of exploring a subset of all the possible combinations (which does not
|
||||
# include the deps alternatives) that attempts resembling real-world use cases.
|
||||
#
|
||||
# We validate each ruleset by loading its plugin dependencies at different
|
||||
# versions, with the following logic:
|
||||
# - for all the plugin dependencies defined in the ruleset:
|
||||
# - we take the plugin version of the dependency
|
||||
# - we set the patch version number to 0, to forbid patch-level dependencies
|
||||
# (e.g. falco will fail the validation if v0.8.1 of a plugin is required and we provide v0.8.0)
|
||||
# - iteratively:
|
||||
# - for all the plugin dependencies defined in the ruleset:
|
||||
# - we download the plugin at the given version of the dependency by using falcoctl
|
||||
# - we increase the minor version number of the plugin by 1
|
||||
# - we validate the ruleset with Falco and stop if we encounter an error
|
||||
# - if falcoctl didn't find any updated plugin with the increased minor
|
||||
# version for any of the plugin deps, we stop iterating
|
||||
#
|
||||
# todo(jasondellaluce): improve this by attempting more cases
|
||||
# todo(jasondellaluce): if we skip one minor version (e.g. bump from v0.1.0
|
||||
# to v0.3.0), this algorithm would stop before finishing the exploration
|
||||
- name: Validate plugin and rules
|
||||
run: |
|
||||
set -e pipefail
|
||||
|
||||
if [ ! -d "${{ steps.get-config.outputs.rules_dir }}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sudo mkdir -p /usr/share/falco/plugins
|
||||
|
||||
rules_files=$(ls ${{ steps.get-config.outputs.rules_dir }}/*)
|
||||
deps=$(./.github/extract-plugins-deps-from-rulesfile.sh \
|
||||
"${{ inputs.plugin }}" \
|
||||
"$rules_files")
|
||||
echo "Deps: ${deps}"
|
||||
ver_diff=0
|
||||
has_updates=1
|
||||
while [ "$has_updates" -eq 1 ]; do
|
||||
has_updates=0
|
||||
for dep in $deps; do
|
||||
echo "Plugin: ${dep}"
|
||||
plugin_name=$(echo $dep | tr -d '"' | cut -d ':' -f 1)
|
||||
|
||||
# forcing zero patch version to forbid patch-like dependencies
|
||||
# bumping minor version at every iteration
|
||||
plugin_ver=$(echo $dep | tr -d '"' | cut -d ':' -f 2)
|
||||
plugin_ver_major=$(echo $plugin_ver | cut -d '.' -f 1)
|
||||
plugin_ver_minor=$(expr $(echo $plugin_ver | cut -d '.' -f 2) + $ver_diff)
|
||||
plugin_ver_patch=0
|
||||
plugin_ver="${plugin_ver_major}.${plugin_ver_minor}.${plugin_ver_patch}"
|
||||
|
||||
set +e pipefail
|
||||
sudo falcoctl artifact install ${plugin_name}:${plugin_ver}
|
||||
if [ $? -eq 0 ]; then
|
||||
echo Installed plugin "${plugin_name}" at version "${plugin_ver}"
|
||||
has_updates=1
|
||||
else
|
||||
echo Can\'t pull plugin "${plugin_name}" at version "${plugin_ver}"
|
||||
echo Attempt installing locally-built plugin "${plugin_name}"...
|
||||
for archive in $(ls /tmp/plugins-${{ inputs.arch }}/${plugin_name}-*); do
|
||||
echo Extracting archive "$archive"...
|
||||
mkdir -p tmpdir && pushd tmpdir
|
||||
tar -xvf $archive
|
||||
sudo cp -r *.so /usr/share/falco/plugins || true
|
||||
popd && rm -fr tmpdir
|
||||
done
|
||||
fi
|
||||
set -e pipefail
|
||||
done
|
||||
ver_diff=$(expr $ver_diff + 1)
|
||||
|
||||
./.github/validate-rules.sh \
|
||||
"${{ inputs.falco-image }}" \
|
||||
"${{ inputs.rules-checker }}" \
|
||||
"${{ steps.get-config.outputs.config_file }}" \
|
||||
"$rules_files"
|
||||
done
|
|
@ -1,10 +1,7 @@
|
|||
*~
|
||||
.vscode
|
||||
.DS_Store
|
||||
.idea
|
||||
output/
|
||||
plugins/*/*.so
|
||||
plugins/*/lib*.h
|
||||
plugins/dummy_c/nlohmann
|
||||
plugins/dummy_c/include
|
||||
plugins/dummy_c/*.tar.gz
|
||||
plugins/dummy_c/sdk
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
repos:
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: 'v18.1.3'
|
||||
hooks:
|
||||
- id: clang-format
|
||||
name: clang-format-18
|
||||
files: ^plugins/container/.*$
|
||||
exclude: plugin_config_schema\.h
|
||||
stages: [pre-commit]
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: 'v14.0.6'
|
||||
hooks:
|
||||
- id: clang-format
|
||||
name: clang-format-14
|
||||
files: ^plugins/(k8smeta|dummy_c)/.*$
|
||||
stages: [pre-commit]
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: rust-fmt
|
||||
name: rust-fmt
|
||||
description: Format files with rustfmt.
|
||||
entry: rustfmt +nightly --color always
|
||||
types: [rust]
|
||||
language: system
|
||||
stages: [pre-commit]
|
||||
- id: dco
|
||||
name: dco
|
||||
entry: ./tools/local_hooks/dco-pre-commit-msg.sh
|
||||
language: script
|
||||
stages: [prepare-commit-msg]
|
121
Makefile
121
Makefile
|
@ -1,6 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2023 The Falco Authors.
|
||||
# Copyright (C) 2022 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
|
@ -15,8 +14,9 @@
|
|||
SHELL := /bin/bash
|
||||
GO ?= $(shell which go)
|
||||
|
||||
FALCOSECURITY_LIBS_REVISION=e25e44b3ba4cb90ba9ac75bf747978e41fb6b221
|
||||
|
||||
DEBUG = 1
|
||||
PRE_RELEASE = --pre-release
|
||||
OUTPUT_DIR := output
|
||||
SOURCE_DIR := plugins
|
||||
ARCH ?=$(shell uname -m)
|
||||
|
@ -24,31 +24,18 @@ PLATFORM ?=$(shell uname -s | tr '[:upper:]' '[:lower:]')
|
|||
|
||||
plugins = $(shell ls -d ${SOURCE_DIR}/*/ | cut -f2 -d'/' | xargs)
|
||||
plugins-clean = $(addprefix clean/,$(plugins))
|
||||
plugins-changelogs = $(addprefix changelog/,$(plugins))
|
||||
plugins-packages = $(addprefix package/,$(plugins))
|
||||
plugins-releases = $(addprefix release/,$(plugins))
|
||||
plugins-tidy = $(addprefix tidy/,$(plugins))
|
||||
|
||||
.PHONY: all
|
||||
all: check-registry $(plugins)
|
||||
|
||||
.PHONY: $(plugins)
|
||||
$(plugins): build/readme/readme
|
||||
+cd plugins/$@ && make DEBUG=$(DEBUG)
|
||||
# make rules, if any
|
||||
+@cd plugins/$@ \
|
||||
&& make rules \
|
||||
&& echo "$@ rules generated" || :
|
||||
# make readme, if any
|
||||
+@cd plugins/$@ \
|
||||
&& make readme READMETOOL=../../build/readme/bin/readme \
|
||||
&& echo "$@ readme generated" || :
|
||||
|
||||
tidy/%:
|
||||
+cd plugins/$@ && [-f go.mod] && $(GO) mod tidy
|
||||
$(plugins):
|
||||
cd plugins/$@ && make DEBUG=$(DEBUG)
|
||||
|
||||
.PHONY: clean
|
||||
clean: $(plugins-clean) clean/packages clean/build/utils/version clean/build/registry/registry clean/build/changelog/changelog clean/build/readme/readme
|
||||
clean: $(plugins-clean) clean/packages clean/build/utils/version clean/build/registry/registry
|
||||
|
||||
.PHONY: clean/packages
|
||||
clean/packages:
|
||||
|
@ -56,101 +43,67 @@ clean/packages:
|
|||
|
||||
.PHONY: $(plugins-clean)
|
||||
$(plugins-clean):
|
||||
+cd plugins/$(shell basename $@) && make clean
|
||||
|
||||
.PHONY: $(plugins-tidy)
|
||||
$(plugins-tidy):
|
||||
+cd plugins/$(shell basename $@) && [ -f go.mod ] && $(GO) mod tidy || true
|
||||
|
||||
.PHONY: tidy
|
||||
tidy: $(plugins-tidy)
|
||||
+cd build/utils && $(GO) mod tidy
|
||||
+cd build/readme && $(GO) mod tidy
|
||||
+cd build/registry && $(GO) mod tidy
|
||||
+cd build/utils && $(GO) mod tidy
|
||||
cd plugins/$(shell basename $@) && make clean
|
||||
|
||||
.PHONY: packages
|
||||
packages: clean/packages $(plugins-packages)
|
||||
packages: clean/packages $(plugins-clean) $(plugins-packages)
|
||||
|
||||
package/%: clean/% % build/utils/version
|
||||
.PHONY: releases
|
||||
releases: $(plugins-releases)
|
||||
|
||||
.PHONY: $(plugins-packages)
|
||||
$(plugins-packages): all build/utils/version
|
||||
$(eval PLUGIN_NAME := $(shell basename $@))
|
||||
$(eval PLUGIN_PATH := plugins/$(PLUGIN_NAME)/lib$(PLUGIN_NAME).so)
|
||||
$(eval PLUGIN_VERSION := $(shell ./build/utils/version --path $(PLUGIN_PATH) $(PRE_RELEASE) | tail -n 1))
|
||||
$(eval PLUGIN_VERSION := $(shell ./build/utils/version --path $(PLUGIN_PATH) --pre-release | tail -n 1))
|
||||
# re-run command to stop in case of non-zero exit code
|
||||
@./build/utils/version --path $(PLUGIN_PATH) $(PRE_RELEASE)
|
||||
@./build/utils/version --path $(PLUGIN_PATH) --pre-release
|
||||
mkdir -p $(OUTPUT_DIR)/$(PLUGIN_NAME)
|
||||
cp -r $(PLUGIN_PATH) $(OUTPUT_DIR)/$(PLUGIN_NAME)/
|
||||
cp -r plugins/$(PLUGIN_NAME)/README.md $(OUTPUT_DIR)/$(PLUGIN_NAME)/
|
||||
tar -zcvf $(OUTPUT_DIR)/$(PLUGIN_NAME)-$(PLUGIN_VERSION)-${PLATFORM}-${ARCH}.tar.gz -C ${OUTPUT_DIR}/$(PLUGIN_NAME) $$(ls -A ${OUTPUT_DIR}/$(PLUGIN_NAME))
|
||||
rm -rf $(OUTPUT_DIR)/$(PLUGIN_NAME)
|
||||
@echo "$(PLUGIN_NAME) package built"
|
||||
# build rules package, if any
|
||||
mkdir -p $(OUTPUT_DIR)/$(PLUGIN_NAME)-rules
|
||||
# symlinks are ignored when creating the rules package. Only regular files are considered.
|
||||
find plugins/$(PLUGIN_NAME)/rules/* -type f -exec cp -t $(OUTPUT_DIR)/$(PLUGIN_NAME)-rules/ {} + && \
|
||||
tar -zcvf $(OUTPUT_DIR)/$(PLUGIN_NAME)-rules-$(PLUGIN_VERSION).tar.gz -C \
|
||||
$(OUTPUT_DIR)/$(PLUGIN_NAME)-rules $$(ls -A ${OUTPUT_DIR}/$(PLUGIN_NAME)-rules) || :
|
||||
@test $(OUTPUT_DIR)/$(PLUGIN_NAME)-rules-$(PLUGIN_VERSION).tar.gz && echo "$(PLUGIN_NAME) rules package built"
|
||||
rm -rf $(OUTPUT_DIR)/$(PLUGIN_NAME)-rules
|
||||
|
||||
release/%: DEBUG=0
|
||||
release/%: PRE_RELEASE=
|
||||
release/%: clean package/%
|
||||
@echo "$(PLUGIN_NAME) released"
|
||||
|
||||
.PHONY: changelogs
|
||||
changelogs: $(plugins-changelogs)
|
||||
|
||||
changelog/%: build/changelog/changelog
|
||||
release/%: clean/% % build/utils/version
|
||||
$(eval PLUGIN_NAME := $(shell basename $@))
|
||||
$(eval CHANGELOG_PATH := plugins/$(PLUGIN_NAME)/CHANGELOG.md)
|
||||
@./changelog-gen.sh $(PLUGIN_NAME) > $(CHANGELOG_PATH)
|
||||
@echo "$(CHANGELOG_PATH) generated"
|
||||
$(eval PLUGIN_PATH := plugins/$(PLUGIN_NAME)/lib$(PLUGIN_NAME).so)
|
||||
$(eval PLUGIN_VERSION := $(shell ./build/utils/version --path $(PLUGIN_PATH) | tail -n 1))
|
||||
# re-run command to stop in case of non-zero exit code
|
||||
@./build/utils/version --path $(PLUGIN_PATH)
|
||||
mkdir -p $(OUTPUT_DIR)/$(PLUGIN_NAME)
|
||||
cp -r $(PLUGIN_PATH) $(OUTPUT_DIR)/$(PLUGIN_NAME)/
|
||||
cp -r plugins/$(PLUGIN_NAME)/README.md $(OUTPUT_DIR)/$(PLUGIN_NAME)/
|
||||
tar -zcvf $(OUTPUT_DIR)/$(PLUGIN_NAME)-$(PLUGIN_VERSION)-${PLATFORM}-${ARCH}.tar.gz -C ${OUTPUT_DIR}/$(PLUGIN_NAME) $$(ls -A ${OUTPUT_DIR}/$(PLUGIN_NAME))
|
||||
|
||||
.PHONY: check-registry
|
||||
check-registry: build/registry/registry
|
||||
@build/registry/bin/registry check ./registry.yaml
|
||||
@build/registry/registry check ./registry.yaml
|
||||
@echo The plugin registry is OK
|
||||
|
||||
.PHONY: update-readme
|
||||
update-readme: build/registry/registry
|
||||
@build/registry/bin/registry table ./registry.yaml \
|
||||
@build/registry/registry table ./registry.yaml \
|
||||
--subfile=./README.md \
|
||||
--subtag="<!-- REGISTRY:TABLE -->"
|
||||
--subtag="<!-- REGISTRY:SOURCE-TABLE -->" \
|
||||
--type=plugins-source
|
||||
@build/registry/registry table ./registry.yaml \
|
||||
--subfile=./README.md \
|
||||
--subtag="<!-- REGISTRY:EXTRACTOR-TABLE -->" \
|
||||
--type=plugins-extractor
|
||||
@echo Readme has been updated successfully
|
||||
|
||||
.PHONY: update-index
|
||||
update-index: build/registry/registry
|
||||
@build/registry/bin/registry update-index ./registry.yaml ${DIST_INDEX}
|
||||
@echo Distribution index has been updated successfully
|
||||
|
||||
.PHONY: build/utils/version
|
||||
build/utils/version:
|
||||
+@cd build/utils && make
|
||||
@cd build/utils && make
|
||||
|
||||
.PHONY: clean/build/utils/version
|
||||
clean/build/utils/version:
|
||||
+@cd build/utils && make clean
|
||||
@cd build/utils && make clean
|
||||
|
||||
.PHONY: build/registry/registry
|
||||
build/registry/registry:
|
||||
+@cd build/registry && make
|
||||
@cd build/registry && make
|
||||
|
||||
.PHONY: clean/build/registry/registry
|
||||
clean/build/registry/registry:
|
||||
+@cd build/registry && make clean
|
||||
|
||||
.PHONY: build/changelog/changelog
|
||||
build/changelog/changelog:
|
||||
+@cd build/changelog && make
|
||||
|
||||
.PHONY: clean/build/changelog/changelog
|
||||
clean/build/changelog/changelog:
|
||||
+@cd build/changelog && make clean
|
||||
|
||||
.PHONY: build/readme/readme
|
||||
build/readme/readme:
|
||||
+@cd build/readme && make
|
||||
|
||||
.PHONY: clean/build/readme/readme
|
||||
clean/build/readme/readme:
|
||||
+@cd build/readme && make clean
|
||||
@cd build/registry && make clean
|
||||
|
|
16
OWNERS
16
OWNERS
|
@ -1,10 +1,14 @@
|
|||
approvers:
|
||||
- mstemm
|
||||
- leogr
|
||||
- jasondellaluce
|
||||
- LucaGuerra
|
||||
- ekoops
|
||||
emeritus_approvers:
|
||||
- ldegio
|
||||
- leodido
|
||||
- fntlnz
|
||||
- mstemm
|
||||
- leogr
|
||||
- jasondellaluce
|
||||
reviewers:
|
||||
- ldegio
|
||||
- leodido
|
||||
- fntlnz
|
||||
- mstemm
|
||||
- leogr
|
||||
- jasondellaluce
|
||||
|
|
148
README.md
148
README.md
|
@ -1,124 +1,78 @@
|
|||
# Plugins
|
||||
|
||||
[](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#core-scope) [](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable) [](./LICENSE)
|
||||

|
||||
[](./LICENSE)
|
||||
|
||||
This repository is the central hub for the Falco Plugin ecosystem. It serves two main purposes:
|
||||
Note: *The plugin system is a new feature introduced since Falco 0.31.0. You can find more detail in the original [proposal document](https://github.com/falcosecurity/falco/blob/master/proposals/20210501-plugin-system.md).*
|
||||
|
||||
- **Be a registry:** A comprehensive catalog of plugins recognized by The Falco Project, regardless of where their source code is hosted.
|
||||
- **Monorepo for Falcosecurity plugins:** Official plugins hosted and maintained by The Falco Project, with robust release and distribution processes.
|
||||
|
||||
For more information about the plugin system’s architecture and concepts, please see the [official documentation](https://falco.org/docs/plugins).
|
||||
|
||||
---
|
||||
This repository contains the [Plugin Registry](#plugin-registry) and the [plugins officially maintained](#falcusecurity-plugins) by the Falcosecurity organization. [Plugins](https://falco.org/docs/plugins) can be used to extend [Falco](https://github.com/falcosecurity/falco) and of applications using [Falcosecurity libs](https://github.com/falcosecurity/libs). Please refer to the [official documentation](https://falco.org/docs/plugins) to better understand the plugin system's concepts and architecture.
|
||||
|
||||
## Plugin Registry
|
||||
|
||||
The registry contains metadata and information about every plugin known and recognized by the Falcosecurity organization. It lists plugins hosted either in this repository or in other repositories. These plugins are developed for Falco and made available to the community.
|
||||
The Registry contains metadata and information about every plugin known and recognized by the Falcosecurity organization. It lists plugins hosted either in this repository or in other repositories. These plugins are developed for Falco and made available to the community. Check out the sections below to know how to [register your plugins](#registering-a-new-plugin) and see plugins currently contained in the registry.
|
||||
|
||||
> Check out the [Registering a Plugin](./docs/registering-a-plugin.md) to know how to add your plugin to this registry.
|
||||
### Registering a new Plugin
|
||||
|
||||
Registering your plugin inside the registry helps ensure that some technical constraints are respected, such as that a [given ID is used by exactly one source plugin](https://falco.org/docs/plugins/#plugin-event-ids) and allows source plugin authors and extractor plugin authors to [coordinate event source formats](https://falco.org/docs/plugins/#plugin-event-sources-and-interoperability). Moreover, this is a great way to share your plugin project with the community and engage with it, thus gaining new users and **increasing its visibility**. We encourage you to register your plugin in this registry before publishing it. You can add your plugins in this registry regardless of where its source code is hosted (there's a `url` field for this specifically).
|
||||
|
||||
The registration process involves adding an entry about your plugin inside the [registry.yaml](./registry.yaml) file by creating a Pull Request in this repository. Please be mindful of a few constraints that are automatically checked and required for your plugin to be accepted:
|
||||
|
||||
- The `name` field is mandatory and must be **unique** across all the plugins in the registry
|
||||
- *(Source plugins only)* The `id` field is mandatory and must be **unique** across all the source plugins in the registry
|
||||
- The plugin `name` and `source` fields should match this [regular expression](https://en.wikipedia.org/wiki/Regular_expression): `^[a-z]+[a-z0-9_]*$`
|
||||
|
||||
For reference, here's an example of a source plugin entry:
|
||||
```yaml
|
||||
- id: 2
|
||||
source: aws_cloudtrail
|
||||
name: cloudtrail
|
||||
description: ...
|
||||
authors: The Falco Authors
|
||||
contact: https://falco.org/community
|
||||
url: ...
|
||||
license: Apache-2.0
|
||||
```
|
||||
|
||||
You can find the full registry specification here: *(coming soon...)*
|
||||
|
||||
### Registered Plugins
|
||||
|
||||
The tables below list all the plugins currently registered. The tables are automatically generated from the [registry.yaml](./registry.yaml) file.
|
||||
|
||||
<!-- The text inside \<!-- REGISTRY:xxx --\> comments is auto-generated.
|
||||
These comments and the text between them should not be edited by hand -->
|
||||
<!-- REGISTRY:TABLE -->
|
||||
| Name | Capabilities | Description
|
||||
| --- | --- | --- |
|
||||
| plugin-id-zero-value | **Event Sourcing** <br/>ID: 0 <br/>`` | This ID is reserved for particular purposes and cannot be registered. A plugin author should not use this ID unless specified by the documentation. <br/><br/> Authors: N/A <br/> License: N/A |
|
||||
| test | **Event Sourcing** <br/>ID: 999 <br/>`test` | This ID is reserved for source plugin development. Any plugin author can use this ID, but authors can expect events from other developers with this ID. After development is complete, the author should request an actual ID <br/><br/> Authors: N/A <br/> License: N/A |
|
||||
| [k8saudit](https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit) | **Event Sourcing** <br/>ID: 1 <br/>`k8s_audit` <br/>**Field Extraction** <br/> `k8s_audit` | Read Kubernetes Audit Events and monitor Kubernetes Clusters <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [cloudtrail](https://github.com/falcosecurity/plugins/tree/main/plugins/cloudtrail) | **Event Sourcing** <br/>ID: 2 <br/>`aws_cloudtrail` <br/>**Field Extraction** <br/> `aws_cloudtrail` | Reads Cloudtrail JSON logs from files/S3 and injects as events <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [json](https://github.com/falcosecurity/plugins/tree/main/plugins/json) | **Field Extraction** <br/> *All Sources* | Extract values from any JSON payload <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [dummy](https://github.com/falcosecurity/plugins/tree/main/plugins/dummy) | **Event Sourcing** <br/>ID: 3 <br/>`dummy` <br/>**Field Extraction** <br/> `dummy` | Reference plugin used to document interface <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [dummy_c](https://github.com/falcosecurity/plugins/tree/main/plugins/dummy_c) | **Event Sourcing** <br/>ID: 4 <br/>`dummy_c` <br/>**Field Extraction** <br/> `dummy_c` | Like dummy, but written in C++ <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [docker](https://github.com/Issif/docker-plugin) | **Event Sourcing** <br/>ID: 5 <br/>`docker` <br/>**Field Extraction** <br/> `docker` | Docker Events <br/><br/> Authors: [Thomas Labarussias](https://github.com/Issif) <br/> License: Apache-2.0 |
|
||||
| [seccompagent](https://github.com/kinvolk/seccompagent) | **Event Sourcing** <br/>ID: 6 <br/>`seccompagent` <br/>**Field Extraction** <br/> `seccompagent` | Seccomp Agent Events <br/><br/> Authors: [Alban Crequy](https://github.com/kinvolk/seccompagent) <br/> License: Apache-2.0 |
|
||||
| [okta](https://github.com/falcosecurity/plugins/tree/main/plugins/okta) | **Event Sourcing** <br/>ID: 7 <br/>`okta` <br/>**Field Extraction** <br/> `okta` | Okta Log Events <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [github](https://github.com/falcosecurity/plugins/tree/main/plugins/github) | **Event Sourcing** <br/>ID: 8 <br/>`github` <br/>**Field Extraction** <br/> `github` | Github Webhook Events <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [k8saudit-eks](https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit-eks) | **Event Sourcing** <br/>ID: 9 <br/>`k8s_audit` <br/>**Field Extraction** <br/> `k8s_audit` | Read Kubernetes Audit Events from AWS EKS Clusters <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [nomad](https://github.com/albertollamaso/nomad-plugin/tree/main) | **Event Sourcing** <br/>ID: 10 <br/>`nomad` <br/>**Field Extraction** <br/> `nomad` | Read Hashicorp Nomad Events Stream <br/><br/> Authors: [Alberto Llamas](https://github.com/albertollamaso/nomad-plugin/issues) <br/> License: Apache-2.0 |
|
||||
| [dnscollector](https://github.com/SysdigDan/dnscollector-falco-plugin) | **Event Sourcing** <br/>ID: 11 <br/>`dnscollector` <br/>**Field Extraction** <br/> `dnscollector` | DNS Collector Events <br/><br/> Authors: [Daniel Moloney](https://github.com/SysdigDan/dnscollector-falco-plugin/issues) <br/> License: Apache-2.0 |
|
||||
| [gcpaudit](https://github.com/falcosecurity/plugins/tree/main/plugins/gcpaudit) | **Event Sourcing** <br/>ID: 12 <br/>`gcp_auditlog` <br/>**Field Extraction** <br/> `gcp_auditlog` | Read GCP Audit Logs <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [syslogsrv](https://github.com/nabokihms/syslogsrv-falco-plugin/tree/main/plugins/syslogsrv) | **Event Sourcing** <br/>ID: 13 <br/>`syslogsrv` <br/>**Field Extraction** <br/> `syslogsrv` | Syslog Server Events <br/><br/> Authors: [Maksim Nabokikh](https://github.com/nabokihms/syslogsrv-falco-plugin/issues) <br/> License: Apache-2.0 |
|
||||
| [salesforce](https://github.com/an1245/falco-plugin-salesforce/) | **Event Sourcing** <br/>ID: 14 <br/>`salesforce` <br/>**Field Extraction** <br/> `salesforce` | Falco plugin providing basic runtime threat detection and auditing logging for Salesforce <br/><br/> Authors: [Andy](https://github.com/an1245/falco-plugin-salesforce/issues) <br/> License: Apache-2.0 |
|
||||
| [box](https://github.com/an1245/falco-plugin-box/) | **Event Sourcing** <br/>ID: 15 <br/>`box` <br/>**Field Extraction** <br/> `box` | Falco plugin providing basic runtime threat detection and auditing logging for Box <br/><br/> Authors: [Andy](https://github.com/an1245/falco-plugin-box/issues) <br/> License: Apache-2.0 |
|
||||
| [k8smeta](https://github.com/falcosecurity/plugins/tree/main/plugins/k8smeta) | **Field Extraction** <br/> `syscall` | Enriche Falco syscall flow with Kubernetes Metadata <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [k8saudit-gke](https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit-gke) | **Event Sourcing** <br/>ID: 16 <br/>`k8s_audit` <br/>**Field Extraction** <br/> `k8s_audit` | Read Kubernetes Audit Events from GKE Clusters <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [journald](https://github.com/gnosek/falco-journald-plugin) | **Event Sourcing** <br/>ID: 17 <br/>`journal` <br/>**Field Extraction** <br/> `journal` | Read Journald events into Falco <br/><br/> Authors: [Grzegorz Nosek](https://github.com/gnosek/falco-journald-plugin) <br/> License: Apache-2.0 |
|
||||
| [kafka](https://github.com/falcosecurity/plugins/tree/main/plugins/kafka) | **Event Sourcing** <br/>ID: 18 <br/>`kafka` | Read events from Kafka topics into Falco <br/><br/> Authors: [Hunter Madison](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [gitlab](https://github.com/an1245/falco-plugin-gitlab) | **Event Sourcing** <br/>ID: 19 <br/>`gitlab` <br/>**Field Extraction** <br/> `gitlab` | Falco plugin providing basic runtime threat detection and auditing logging for GitLab <br/><br/> Authors: [Andy](https://github.com/an1245/falco-plugin-gitlab/issues) <br/> License: Apache-2.0 |
|
||||
| [keycloak](https://github.com/mattiaforc/falco-keycloak-plugin) | **Event Sourcing** <br/>ID: 20 <br/>`keycloak` <br/>**Field Extraction** <br/> `keycloak` | Falco plugin for sourcing and extracting Keycloak user/admin events <br/><br/> Authors: [Mattia Forcellese](https://github.com/mattiaforc/falco-keycloak-plugin/issues) <br/> License: Apache-2.0 |
|
||||
| [k8saudit-aks](https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit-aks) | **Event Sourcing** <br/>ID: 21 <br/>`k8s_audit` <br/>**Field Extraction** <br/> `k8s_audit` | Read Kubernetes Audit Events from Azure AKS Clusters <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [k8saudit-ovh](https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit-ovh) | **Event Sourcing** <br/>ID: 22 <br/>`k8s_audit` <br/>**Field Extraction** <br/> `k8s_audit` | Read Kubernetes Audit Events from OVHcloud MKS Clusters <br/><br/> Authors: [Aurélie Vache](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [dummy_rs](https://github.com/falcosecurity/plugins/tree/main/plugins/dummy_rs) | **Event Sourcing** <br/>ID: 23 <br/>`dummy_rs` <br/>**Field Extraction** <br/> `dummy_rs` | Like dummy, but written in Rust <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [container](https://github.com/falcosecurity/plugins/tree/main/plugins/container) | **Field Extraction** <br/> `syscall` | Enriche Falco syscall flow with Container Metadata <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [krsi](https://github.com/falcosecurity/plugins/tree/main/plugins/krsi) | **Field Extraction** <br/> `syscall` | Security (KRSI) events support for Falco <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [collector](https://github.com/falcosecurity/plugins/tree/main/plugins/collector) | **Event Sourcing** <br/>ID: 24 <br/>`collector` | Generic collector to ingest raw payloads into Falco <br/><br/> Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| [awselb](https://github.com/yukinakanaka/falco-plugin-aws-elb) | **Event Sourcing** <br/>ID: 25 <br/>`awselb` <br/>**Field Extraction** <br/> `awselb` | AWS Elastic Load Balancer access logs events <br/><br/> Authors: [Yuki Nakamura](https://github.com/yukinakanaka/falco-plugin-aws-elb/issues) <br/> License: Apache-2.0 |
|
||||
<!-- The text inside \<!-- REGISTRY:xxx --\> comments is auto-generated. These comments and the text between them should not be edited by hand -->
|
||||
|
||||
<!-- REGISTRY:TABLE -->
|
||||
#### Source Plugins
|
||||
<!-- REGISTRY:SOURCE-TABLE -->
|
||||
| ID | Name | Event Source | Description | Info |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | k8s_audit | `k8s_audit` | Reserved for a future back-port of Falco's k8s_audit event source as a plugin | Authors: N/A <br/> License: N/A |
|
||||
| 2 | [cloudtrail](https://github.com/falcosecurity/plugins/tree/master/plugins/cloudtrail) | `aws_cloudtrail` | Reads Cloudtrail JSON logs from files/S3 and injects as events | Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| 3 | [dummy](https://github.com/falcosecurity/plugins/tree/master/plugins/dummy) | `dummy` | Reference plugin used to document interface | Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| 4 | [dummy_c](https://github.com/falcosecurity/plugins/tree/master/plugins/dummy_c) | `dummy_c` | Like Dummy, but written in C++ | Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
| 5 | [docker](https://github.com/Issif/docker-plugin) | `docker` | Docker Events | Authors: [Thomas Labarussias](https://github.org/Issif) <br/> License: Apache-2.0 |
|
||||
| 999 | test | `test` | This ID is reserved for source plugin development. Any plugin author can use this ID, but authors can expect events from other developers with this ID. After development is complete, the author should request an actual ID | Authors: N/A <br/> License: N/A |
|
||||
|
||||
## Falcosecurity Plugins
|
||||
<!-- REGISTRY:SOURCE-TABLE -->
|
||||
|
||||
Along with the registry, this repository hosts the official plugins maintained by the Falcosecurity organization. Each plugin is an independent project with its own directory in the [plugins folder](https://github.com/falcosecurity/plugins/tree/main/plugins).
|
||||
#### Extractor Plugins
|
||||
<!-- REGISTRY:EXTRACTOR-TABLE -->
|
||||
| Name | Extract Event Sources | Description | Info |
|
||||
| --- | --- | --- | --- |
|
||||
| [json](https://github.com/falcosecurity/plugins/tree/master/plugins/json) | N/A | Extract values from any JSON payload | Authors: [The Falco Authors](https://falco.org/community) <br/> License: Apache-2.0 |
|
||||
|
||||
The `main` branch reflects the latest development state, and plugins are released on a regular basis. Development builds are published automatically when a Pull Request is merged into `main`, while stable builds are released only when a new tag is created. You can find all published artifacts at [download.falco.org](https://download.falco.org/?prefix=plugins). For details on the release process, please see our [Release Process](./release.md).
|
||||
<!-- REGISTRY:EXTRACTOR-TABLE -->
|
||||
|
||||
The instructions below explain how to install and apply only to plugins from this repository.
|
||||
## Hosted Plugins
|
||||
|
||||
### Installing Plugins
|
||||
Another purpose of this repository is to host and maintain the plugins owned by the Falcosecurity organization. Each plugin is a standalone project and has its own directory, and they are all inside the [plugins](https://github.com/falcosecurity/plugins/tree/master/plugins) folder.
|
||||
|
||||
Plugins hosted in this repository are built and distributed through Falco's official channels. You can easily install them using either [falcoctl](https://github.com/falcosecurity/falcoctl) or the [Falco Helm chart](https://github.com/falcosecurity/charts/tree/master/charts/falco).
|
||||
The `master` branch contains the most up-to-date state of development, and each plugin is regularly released. Please check our [Release Process](./release.md) to know how plugins are released and how artifacts are distributed. Dev builds are published each time a Pull Request gets merged into `master`, whereas stable builds are released and published only when a new release gets tagged. You can find the published artifacts at https://download.falco.org/?prefix=plugins.
|
||||
|
||||
#### Using falcoctl
|
||||
|
||||
1. **Install falcoctl:** If you haven't already, follow the [falcoctl installation guide](https://github.com/falcosecurity/falcoctl?tab=readme-ov-file#installation).
|
||||
2. **Install a Plugin:** Execute the following command, replacing `<plugin-name>` with the name of the plugin you wish to install:
|
||||
```bash
|
||||
falcoctl index update falcosecurity
|
||||
falcoctl artifact install <plugin-name>
|
||||
```
|
||||
> Depending on your environment, you may need to run the above commands with `sudo`.
|
||||
3. Configure Falco to load the plugin as described in the [plugin's documentation](https://falco.org/docs/concepts/plugins/usage/#loading-plugins-in-falco).
|
||||
|
||||
|
||||
#### Using the Falco Helm Chart
|
||||
|
||||
When installing Falco using the Helm chart, you can instruct the chart to install a specific plugin by setting the `falcoctl.config.artifact.install.refs` value and then adding the relevant plugin configuration under `falco`.
|
||||
|
||||
The Helm charts provides a preset [values-k8saudit.yaml](https://github.com/falcosecurity/charts/blob/master/charts/falco/values-k8saudit.yaml) file that can be used to install the `k8saudit` plugin or as example for installing other plugins.
|
||||
If you wish to contribute your plugin to the Falcosecurity organization, you just need to open a Pull Request to add it inside the `plugins` folder and to add it inside the registry. In order to be hosted in this repository, plugins must be licensed under the [Apache 2.0 License](./LICENSE).
|
||||
|
||||
## Contributing
|
||||
|
||||
If you want to help and wish to contribute, please review our [contribution guidelines](https://github.com/falcosecurity/.github/blob/main/CONTRIBUTING.md). Code contributions are always encouraged and welcome!
|
||||
|
||||
If you wish to contribute a plugin to The Falco Project, simply open a Pull Request to add your plugin to the `/plugins` folder and [update the registry accordingly](./docs/registering-a-plugin.md). Note that to be hosted in this repository, plugins must be licensed under the [Apache 2.0 License](./LICENSE).
|
||||
|
||||
### Enforcing coding style and repo policies locally
|
||||
|
||||
This repository supports enforcing coding style and policies locally through the `pre-commit` framework. `pre-commit`
|
||||
allows to automatically install `git-hooks` that will be executed at every new commit. The following is the list of
|
||||
`git-hooks` defined in `.pre-commit-config.yaml` (notice that some of them only target files written in a specific
|
||||
language):
|
||||
1. the `rust-fmt` hook - a `pre-commit` git hook running `rust fmt` on the staged changes
|
||||
2. the `dco` hook - a `pre-commit-msg` git hook running adding the `DCO` on the commit if not present
|
||||
|
||||
The following steps describe how to install these hooks.
|
||||
|
||||
##### Step 1
|
||||
|
||||
Install `pre-commit` framework following the [official documentation](https://pre-commit.com/#installation).
|
||||
|
||||
> __Please note__: you have to follow only the "Installation" section.
|
||||
|
||||
#### Step 2
|
||||
|
||||
Install `pre-commit` git hooks:
|
||||
```bash
|
||||
pre-commit install --hook-type pre-commit --hook-type prepare-commit-msg --overwrite
|
||||
```
|
||||
If you want to help and wish to contribute, please review our [contribution guidelines](https://github.com/falcosecurity/.github/blob/master/CONTRIBUTING.md). Code contributions are always encouraged and welcome!
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
bin
|
|
@ -1,26 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2023 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
SHELL=/bin/bash -o pipefail
|
||||
|
||||
GO ?= go
|
||||
|
||||
all: bin/changelog
|
||||
|
||||
clean:
|
||||
@rm -fr bin
|
||||
|
||||
bin/changelog: changelog.go
|
||||
@mkdir -p bin
|
||||
@$(GO) build -o bin/changelog changelog.go
|
|
@ -1,172 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/registry"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const (
|
||||
commitHashMaxLen = 7
|
||||
commitLinkFmt = "https://github.com/falcosecurity/plugins/commit/%s"
|
||||
commitMsgMaxLen = 80
|
||||
)
|
||||
|
||||
func git(args ...string) (output []string, err error) {
|
||||
fmt.Fprintln(os.Stderr, "git ", strings.Join(args, " "))
|
||||
stdout, err := exec.Command("git", args...).Output()
|
||||
if err != nil {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
return nil, errors.New("git (" + exitErr.String() + "): " + string(exitErr.Stderr))
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return strings.Split(string(stdout), "\n"), nil
|
||||
}
|
||||
|
||||
// an empty string matches the last tag with no match filtering
|
||||
func gitGetLatestTagWithMatch(match []string) (string, error) {
|
||||
args := []string{"describe", "--tags", "--abbrev=0"}
|
||||
if len(match) > 0 {
|
||||
for _, m := range match {
|
||||
args = append(args, "--match", m)
|
||||
}
|
||||
}
|
||||
tags, err := git(args...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(tags) == 0 {
|
||||
return "", errors.New("git tag not found")
|
||||
}
|
||||
return tags[0], nil
|
||||
}
|
||||
|
||||
// an empty tag lists commit from whole history
|
||||
func gitListCommits(from, to string) ([]string, error) {
|
||||
revRange := ""
|
||||
if len(to) > 0 {
|
||||
revRange = to
|
||||
}
|
||||
if len(from) > 0 {
|
||||
if len(revRange) == 0 {
|
||||
revRange = "HEAD"
|
||||
}
|
||||
revRange = from + ".." + revRange
|
||||
}
|
||||
logs, err := git("log", revRange, "--oneline")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
func pluginSource(pname string) string {
|
||||
reg, err := registry.LoadRegistryFromFile("registry.yaml")
|
||||
if err != nil {
|
||||
fail(fmt.Errorf("an error occurred while loading registry entries from file %q: %v", "registry.yaml", err))
|
||||
}
|
||||
|
||||
for _, plugin := range reg.Plugins {
|
||||
if plugin.Name == pname && plugin.Capabilities.Sourcing.Supported {
|
||||
return plugin.Capabilities.Sourcing.Source
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func fail(err error) {
|
||||
fmt.Printf("error: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// formats the line with markdown syntax and decorates it
|
||||
func formatCommitLine(c string) string {
|
||||
firstSpace := strings.Index(c, " ")
|
||||
hash := strings.Trim(c[:firstSpace], " ") // hash is before the first space
|
||||
message := strings.Trim(c[firstSpace:], " ") // message is after the first space
|
||||
if len(message) > commitMsgMaxLen {
|
||||
message = message[:commitMsgMaxLen-3] + "..."
|
||||
}
|
||||
commitLink := fmt.Sprintf(commitLinkFmt, hash)
|
||||
return fmt.Sprintf("* [`%s`](%s) %s", hash[:commitHashMaxLen], commitLink, message)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var plugin string
|
||||
var from string
|
||||
var to string
|
||||
pflag.StringVar(&plugin, "plugin", "", "Name of the plugin to generate the changelog for")
|
||||
pflag.StringVar(&from, "from", "", "Tag/branch/hash from which start listing commits")
|
||||
pflag.StringVar(&to, "to", "HEAD", "Tag/branch/hash to which stop listing commits")
|
||||
pflag.Parse()
|
||||
|
||||
// if from is not specified, we use the latest tag matching the plugin name
|
||||
if len(from) == 0 {
|
||||
match := []string{}
|
||||
if len(plugin) > 0 {
|
||||
match = append(match, "plugins/"+plugin+"/v[0-9]*.[0-9]*.[0-9]*")
|
||||
match = append(match, plugin+"-[0-9]*.[0-9]*.[0-9]*")
|
||||
}
|
||||
tag, err := gitGetLatestTagWithMatch(match)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "no matching tag found for plugin '"+plugin+"', using commits from whole history:", err.Error())
|
||||
} else {
|
||||
from = tag
|
||||
}
|
||||
}
|
||||
|
||||
// get all commits
|
||||
commits, err := gitListCommits(from, to)
|
||||
if err != nil {
|
||||
fail(err)
|
||||
}
|
||||
|
||||
var rgx, rgxSource, rgxDeps *regexp.Regexp
|
||||
if len(plugin) > 0 {
|
||||
// craft a regex to filter all plugin-related commits that follow
|
||||
// the conventional commit format
|
||||
rgx, _ = regexp.Compile("^[a-f0-9]+ [a-zA-Z]+\\(([a-zA-Z\\/]+\\/)?" + plugin + "(\\/[a-zA-Z\\/]+)?\\):.*")
|
||||
|
||||
// use source name of the plugin as well, if it has sourcing capabilities
|
||||
pluginSource := pluginSource(plugin)
|
||||
if pluginSource != "" {
|
||||
rgxSource, _ = regexp.Compile("^[a-f0-9]+ [a-zA-Z]+\\(([a-zA-Z\\/]+\\/)?" + pluginSource + "(\\/[a-zA-Z\\/]+)?\\):.*")
|
||||
}
|
||||
|
||||
// craft a regex to filter all plugin-related dependabot commits
|
||||
rgxDeps, _ = regexp.Compile("^[a-f0-9]+ build\\(deps\\):.*" + plugin + "$")
|
||||
}
|
||||
|
||||
for _, c := range commits {
|
||||
if len(c) > 0 && (rgx == nil || rgx.MatchString(c) ||
|
||||
(rgxSource != nil && rgxSource.MatchString(c)) ||
|
||||
rgxDeps.MatchString(c)) {
|
||||
fmt.Println(formatCommitLine(c) + "\n")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
module github.com/falcosecurity/plugins/build/changelog
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.24.1
|
||||
|
||||
require (
|
||||
github.com/falcosecurity/plugins/build/registry v0.0.0-20240514080945-0e7ef7698747
|
||||
github.com/spf13/pflag v1.0.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/docker/cli v24.0.5+incompatible // indirect
|
||||
github.com/docker/docker v25.0.6+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.0 // indirect
|
||||
github.com/falcosecurity/falcoctl v0.6.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/afero v1.9.5 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/viper v1.16.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
golang.org/x/oauth2 v0.27.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
oras.land/oras-go/v2 v2.2.1 // indirect
|
||||
)
|
|
@ -1,516 +0,0 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
|
||||
github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg=
|
||||
github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
|
||||
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/falcosecurity/falcoctl v0.6.1 h1:Klg3jHi/PL1Inw9DO9kGpzL6ka+TjI4oDl6kvm1I+VY=
|
||||
github.com/falcosecurity/falcoctl v0.6.1/go.mod h1:4Hx4h3KtcaQzPKxvYn5S9x4IHxwd6QRK9Gu04HHNbhE=
|
||||
github.com/falcosecurity/plugins/build/registry v0.0.0-20240514080945-0e7ef7698747 h1:d+YgxJXgcmu9LX5ixICSTaN3y5MmgCnxW8TfPu5i+Eg=
|
||||
github.com/falcosecurity/plugins/build/registry v0.0.0-20240514080945-0e7ef7698747/go.mod h1:I/unuAO/urquhDsyOE+YmcY0FNBInVtLfZ5VwD3FUMo=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
|
||||
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
|
||||
github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
|
||||
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
oras.land/oras-go/v2 v2.2.1 h1:3VJTYqy5KfelEF9c2jo1MLSpr+TM3mX8K42wzZcd6qE=
|
||||
oras.land/oras-go/v2 v2.2.1/go.mod h1:GeAwLuC4G/JpNwkd+bSZ6SkDMGaaYglt6YK2WvZP7uQ=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
|
@ -1,2 +0,0 @@
|
|||
bin
|
||||
readme
|
|
@ -1,26 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2023 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
SHELL=/bin/bash -o pipefail
|
||||
|
||||
GO ?= go
|
||||
|
||||
all: bin/readme
|
||||
|
||||
clean:
|
||||
@rm -fr bin
|
||||
|
||||
bin/readme: readme.go fields.go
|
||||
@mkdir -p bin
|
||||
@$(GO) build -o bin/readme readme.go fields.go
|
|
@ -1,87 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/falcosecurity/plugin-sdk-go/pkg/loader"
|
||||
"github.com/falcosecurity/plugin-sdk-go/pkg/sdk"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultFieldsTag = "README-PLUGIN-FIELDS"
|
||||
)
|
||||
|
||||
func fieldsRenderArgRow(a *sdk.FieldEntryArg) string {
|
||||
if !a.IsIndex && !a.IsKey {
|
||||
return "None"
|
||||
}
|
||||
|
||||
var res []string
|
||||
if a.IsIndex {
|
||||
res = append(res, "Index")
|
||||
}
|
||||
if a.IsKey {
|
||||
res = append(res, "Key")
|
||||
}
|
||||
if a.IsRequired {
|
||||
res = append(res, "Required")
|
||||
}
|
||||
return strings.Join(res, ", ")
|
||||
}
|
||||
|
||||
// renderNewLines replaces '\n' character with "<br/>" for proper table formatting.
|
||||
func renderNewLines(desc string) string {
|
||||
return strings.ReplaceAll(desc, "\n", "<br/>")
|
||||
}
|
||||
|
||||
func fieldsEditor(p *loader.Plugin, s string) (string, error) {
|
||||
if !p.HasCapExtraction() {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
fields := p.Fields()
|
||||
if len(fields) == 0 {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
table := tablewriter.NewWriter(&buf)
|
||||
table.SetHeader([]string{"Name", "Type", "Arg", "Description"})
|
||||
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
|
||||
table.SetCenterSeparator("|")
|
||||
table.SetRowSeparator("-")
|
||||
table.SetAutoWrapText(false)
|
||||
for _, f := range fields {
|
||||
row := []string{}
|
||||
row = append(row, "`"+f.Name+"`")
|
||||
if f.IsList {
|
||||
row = append(row, "`"+f.Type+" (list)`")
|
||||
} else {
|
||||
row = append(row, "`"+f.Type+"`")
|
||||
}
|
||||
row = append(row, fieldsRenderArgRow(&f.Arg))
|
||||
row = append(row, renderNewLines(f.Desc))
|
||||
table.Append(row)
|
||||
}
|
||||
table.Render()
|
||||
return replateTag(s, fieldsTag, buf.String())
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
module github.com/falcosecurity/plugins/build/readme
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/falcosecurity/plugin-sdk-go v0.7.5
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/spf13/pflag v1.0.6
|
||||
)
|
|
@ -1,33 +0,0 @@
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/falcosecurity/plugin-sdk-go v0.7.5 h1:ke/+kTt0PwedM8+IGTKcW3LrUI/xiJNDCSzqTSW+CvI=
|
||||
github.com/falcosecurity/plugin-sdk-go v0.7.5/go.mod h1:NP+y22DYOS+G3GDXIXNmzf0CBL3nfPPMoQuHvAzfitQ=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -1,102 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/falcosecurity/plugin-sdk-go/pkg/loader"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
pluginPath string
|
||||
readmePath string
|
||||
fieldsTag string
|
||||
)
|
||||
|
||||
type EditorFunc func(*loader.Plugin, string) (string, error)
|
||||
|
||||
func fail(err error) {
|
||||
println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func replateTag(s string, t string, r string) (string, error) {
|
||||
startTag := "<!-- " + t + " -->\n"
|
||||
endTag := "<!-- /" + t + " -->\n"
|
||||
start := 0
|
||||
for {
|
||||
start = strings.Index(s[start:], startTag)
|
||||
if start < 0 {
|
||||
return s, nil
|
||||
}
|
||||
start += len(startTag)
|
||||
end := strings.Index(s[start:], endTag)
|
||||
if end < 0 {
|
||||
return "", fmt.Errorf("can't find end tag: " + endTag)
|
||||
}
|
||||
end += start
|
||||
s = s[:start] + r + s[end:]
|
||||
start += len(r) + len(endTag)
|
||||
}
|
||||
}
|
||||
|
||||
func editFile(plugin *loader.Plugin, path string, editors ...EditorFunc) error {
|
||||
bytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
edited := string(bytes)
|
||||
for _, editor := range editors {
|
||||
edited, err = editor(plugin, edited)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return ioutil.WriteFile(path, ([]byte)(edited), 0)
|
||||
}
|
||||
|
||||
func main() {
|
||||
pflag.StringVarP(&pluginPath, "plugin", "p", "", "File path to the plugin shared library.")
|
||||
pflag.StringVarP(&readmePath, "file", "f", "", "File path to the README file to be edited.")
|
||||
pflag.StringVar(&fieldsTag, "fields-tag", defaultFieldsTag, "Tag to substitute with the plugin fields table.\nIn the file, formatted as \"<!-- TAG -->\\n...\\n<!-- /TAG -->\".")
|
||||
pflag.Parse()
|
||||
if len(pluginPath) == 0 {
|
||||
fail(fmt.Errorf("must specify a plugin path with the -p option"))
|
||||
}
|
||||
if len(readmePath) == 0 {
|
||||
fail(fmt.Errorf("must specify a file path with the -f option"))
|
||||
}
|
||||
|
||||
// load plugin
|
||||
plugin, err := loader.NewPlugin(pluginPath)
|
||||
if err != nil {
|
||||
fail(err)
|
||||
}
|
||||
defer plugin.Unload()
|
||||
|
||||
// use plugin info to edit readme file
|
||||
err = editFile(plugin, readmePath, fieldsEditor)
|
||||
if err != nil {
|
||||
fail(err)
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
bin/*
|
||||
registry
|
|
@ -1,6 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2023 The Falco Authors.
|
||||
# Copyright (C) 2022 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
|
@ -19,8 +18,7 @@ GO ?= go
|
|||
all: registry
|
||||
|
||||
clean:
|
||||
@rm -fr bin
|
||||
@rm -f registry
|
||||
|
||||
registry:
|
||||
@mkdir -p bin
|
||||
@$(GO) build -o bin/registry ./cmd/registry/...
|
||||
registry: *.go
|
||||
@$(GO) build -o registry *.go
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Copyright (C) 2022 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
rgxName *regexp.Regexp
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
rgxName, err = regexp.Compile(`^[a-z]+[a-z0-9_]*$`)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Source) Check(reserved []string) error {
|
||||
|
||||
if s.ID == 0 {
|
||||
return fmt.Errorf("forbidden source ID: '%d'", s.ID)
|
||||
}
|
||||
|
||||
if !rgxName.MatchString(s.Name) {
|
||||
return fmt.Errorf("name does follow the naming convention: '%s'", s.Name)
|
||||
}
|
||||
|
||||
for _, source := range reserved {
|
||||
if s.Source == source {
|
||||
return fmt.Errorf("forbidden source name: '%s'", s.Source)
|
||||
}
|
||||
}
|
||||
|
||||
if !rgxName.MatchString(s.Source) {
|
||||
return fmt.Errorf("source name does follow the naming convention: '%s'", s.Source)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Extractor) Check() error {
|
||||
if !rgxName.MatchString(e.Name) {
|
||||
return fmt.Errorf("name does follow the naming convention: '%s'", e.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugins) Check(reserved []string) error {
|
||||
ids := make(map[uint]bool)
|
||||
names := make(map[string]bool)
|
||||
|
||||
for _, s := range p.Source {
|
||||
if err := s.Check(reserved); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := names[s.Name]; ok {
|
||||
return fmt.Errorf("plugin name is not unique: '%s'", s.Name)
|
||||
}
|
||||
if _, ok := ids[s.ID]; ok {
|
||||
return fmt.Errorf("source id is not unique: '%d'", s.ID)
|
||||
}
|
||||
names[s.Name] = true
|
||||
ids[s.ID] = true
|
||||
}
|
||||
|
||||
for _, e := range p.Extractor {
|
||||
if err := e.Check(); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := names[e.Name]; ok {
|
||||
return fmt.Errorf("plugin name is not unique: '%s'", e.Name)
|
||||
}
|
||||
names[e.Name] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Registry) Check() error {
|
||||
return r.Plugins.Check(r.ReservedSources)
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/cmd/validateRegistry"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/internal/options"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/check"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/distribution"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/oci"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/table"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTableSubTag = "<!-- REGISTRY -->"
|
||||
)
|
||||
|
||||
var (
|
||||
out = bufio.NewWriter(os.Stdout)
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer out.Flush()
|
||||
|
||||
opts := options.NewCommonOptions(
|
||||
options.WithContext(context.Background()),
|
||||
options.WithOutput(out),
|
||||
)
|
||||
|
||||
checkCmd := &cobra.Command{
|
||||
Use: "check <filename>",
|
||||
Short: "Verify the correctness of a plugin registry YAML file",
|
||||
Args: cobra.ExactArgs(1),
|
||||
DisableFlagsInUseLine: true,
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
return check.DoCheck(args[0])
|
||||
},
|
||||
}
|
||||
|
||||
var tableSubFileName string
|
||||
var tableSubTab string
|
||||
tableCmd := &cobra.Command{
|
||||
Use: "table <filename>",
|
||||
Short: "Format a plugin registry YAML file in a MarkDown table",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
return table.DoTable(args[0], tableSubFileName, tableSubTab)
|
||||
},
|
||||
}
|
||||
tableFlags := tableCmd.Flags()
|
||||
tableFlags.StringVar(&tableSubTab, "subtag", defaultTableSubTag, "A tag that delimits the start and the end of the text section to substitute with the generated table.")
|
||||
tableFlags.StringVar(&tableSubFileName, "subfile", "", "If specified, the table will be written inside the file at this path, inserting it between the first two instances of the substitution tag.")
|
||||
|
||||
updateIndexCmd := &cobra.Command{
|
||||
Use: "update-index <registryFilename> <indexFilename>",
|
||||
Short: "Update an index file for artifacts distribution using registry data",
|
||||
Args: cobra.ExactArgs(2),
|
||||
DisableFlagsInUseLine: true,
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
return distribution.DoUpdateIndex(args[0], args[1])
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
pluginsAMD64Path string
|
||||
pluginsARM64Path string
|
||||
rulesfilesPath string
|
||||
devTag string
|
||||
)
|
||||
updateOCIRegistry := &cobra.Command{
|
||||
Use: "update-oci-registry <registryFilename>",
|
||||
Short: "Update the oci registry starting from the registry file and s3 bucket",
|
||||
Args: cobra.ExactArgs(1),
|
||||
DisableFlagsInUseLine: true,
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
status, err := oci.DoUpdateOCIRegistry(opts.Context, args[0], pluginsAMD64Path, pluginsARM64Path, rulesfilesPath, devTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return oci.PrintUpdateStatus(status, opts.Output)
|
||||
},
|
||||
}
|
||||
|
||||
ociFlags := updateOCIRegistry.Flags()
|
||||
ociFlags.StringVar(&pluginsAMD64Path, "plugins-amd64-path", "", "Path to plugins for the amd64 architecture")
|
||||
ociFlags.StringVar(&pluginsARM64Path, "plugins-arm64-path", "", "Path to plugins for the arm64 architecture")
|
||||
ociFlags.StringVar(&rulesfilesPath, "rulesfiles-path", "", "Path to rulesfiles")
|
||||
ociFlags.StringVar(&devTag, "dev-tag", "", "Tag for devel versions")
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "registry",
|
||||
Version: "0.2.0",
|
||||
}
|
||||
rootCmd.AddCommand(checkCmd)
|
||||
rootCmd.AddCommand(tableCmd)
|
||||
rootCmd.AddCommand(updateIndexCmd)
|
||||
rootCmd.AddCommand(updateOCIRegistry)
|
||||
rootCmd.AddCommand(validateRegistry.NewValidateRegistry(context.Background()))
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Printf("error: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package validateRegistry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/falcosecurity/falcoctl/pkg/oci/authn"
|
||||
ocipuller "github.com/falcosecurity/falcoctl/pkg/oci/puller"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/oci"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/registry"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
func NewValidateRegistry(ctx context.Context) *cobra.Command {
|
||||
updateOCIRegistry := &cobra.Command{
|
||||
Use: "validate-registry <registryFilename>",
|
||||
Short: "Check that an OCI repo exists for each plugin in the registry file",
|
||||
Args: cobra.ExactArgs(1),
|
||||
DisableFlagsInUseLine: true,
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
return validateRegistry(ctx, args[0])
|
||||
},
|
||||
}
|
||||
|
||||
return updateOCIRegistry
|
||||
}
|
||||
|
||||
func validateRegistry(ctx context.Context, registryFile string) error {
|
||||
reg, err := registry.LoadRegistryFromFile(registryFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("an error occurred while loading registry entries from file %q: %v", registryFile, err)
|
||||
}
|
||||
|
||||
ociClient := authn.NewClient()
|
||||
|
||||
puller := ocipuller.NewPuller(ociClient, false, nil)
|
||||
// For each plugin in the registry index, look for new ones to be released, and publish them.
|
||||
for _, plugin := range reg.Plugins {
|
||||
// Filter out plugins that are not owned by falcosecurity.
|
||||
if !strings.HasPrefix(plugin.URL, oci.PluginsRepo) {
|
||||
klog.V(2).Infof("skipping plugin %q with authors %q: it is not maintained by %q",
|
||||
plugin.Name, plugin.Authors, oci.FalcoAuthors)
|
||||
continue
|
||||
}
|
||||
klog.Infof("Checking OCI repo for plugin %q", plugin.Name)
|
||||
ref := fmt.Sprintf("ghcr.io/falcosecurity/plugins/plugin/%s:latest", plugin.Name)
|
||||
// We just retrieve the descriptor from the remote repository,
|
||||
// if it fails, likely the repository does not exist
|
||||
if _, err := puller.Descriptor(ctx, ref); err != nil {
|
||||
return fmt.Errorf("plugin %s seems to not have an OCI repository: %w", plugin.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,165 +1,8 @@
|
|||
module github.com/falcosecurity/plugins/build/registry
|
||||
|
||||
go 1.23.4
|
||||
|
||||
toolchain go1.24.1
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/falcosecurity/falcoctl v0.11.0
|
||||
github.com/falcosecurity/plugin-sdk-go v0.7.5
|
||||
github.com/onsi/ginkgo/v2 v2.23.4
|
||||
github.com/onsi/gomega v1.37.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
oras.land/oras-go/v2 v2.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
atomicgo.dev/cursor v0.2.0 // indirect
|
||||
atomicgo.dev/keyboard v0.2.9 // indirect
|
||||
atomicgo.dev/schedule v0.1.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.3 // indirect
|
||||
github.com/cilium/ebpf v0.17.3 // indirect
|
||||
github.com/containerd/console v1.0.4 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/creasty/defaults v1.8.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/cli v27.5.1+incompatible // indirect
|
||||
github.com/docker/docker v27.5.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/falcosecurity/driverkit v0.20.5 // indirect
|
||||
github.com/fatih/camelcase v1.0.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.25.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gookit/color v1.5.4 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/lithammer/fuzzysearch v1.1.8 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/spdystream v0.5.0 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
github.com/moby/sys/user v0.3.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/pterm/pterm v0.12.80 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/viper v1.19.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
|
||||
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250215185904-eff6e970281f // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/oauth2 v0.27.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/term v0.30.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/time v0.10.0 // indirect
|
||||
golang.org/x/tools v0.31.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
k8s.io/api v0.32.3 // indirect
|
||||
k8s.io/apimachinery v0.32.3 // indirect
|
||||
k8s.io/cli-runtime v0.32.2 // indirect
|
||||
k8s.io/client-go v0.32.2 // indirect
|
||||
k8s.io/component-base v0.32.2 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
|
||||
k8s.io/kubectl v0.32.2 // indirect
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.35.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.19.0 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/spf13/cobra v1.3.0
|
||||
)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,52 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
type CommonOptions struct {
|
||||
Output io.Writer
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
type CommonOption func(opts *CommonOptions)
|
||||
|
||||
func NewCommonOptions(opts ...CommonOption) *CommonOptions {
|
||||
o := &CommonOptions{}
|
||||
|
||||
for _, f := range opts {
|
||||
f(o)
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
func WithOutput(out io.Writer) CommonOption {
|
||||
return func(opts *CommonOptions) {
|
||||
opts.Output = out
|
||||
}
|
||||
}
|
||||
|
||||
func WithContext(ctx context.Context) CommonOption {
|
||||
return func(opts *CommonOptions) {
|
||||
opts.Context = ctx
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package check
|
||||
|
||||
import "github.com/falcosecurity/plugins/build/registry/pkg/registry"
|
||||
|
||||
// DoCheck loads the registry.yaml file from disk and validates it.
|
||||
func DoCheck(fileName string) error {
|
||||
registry, err := registry.LoadRegistryFromFile(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return registry.Validate()
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package common
|
||||
|
||||
const (
|
||||
RulesArtifactSuffix = "-rules"
|
||||
// EngineVersionKey is the name given to all the engine requirements.
|
||||
// The same name used by Falco when outputting the engine version.
|
||||
EngineVersionKey = "engine_version_semver"
|
||||
// PluginAPIVersion is the name givet to the plugin api version requirements.
|
||||
// The same name used by Falco when outputting the plugin api version
|
||||
PluginAPIVersion = "plugin_api_version"
|
||||
)
|
|
@ -1,99 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ExtractTarGz extracts a *.tar.gz compressed archive and moves its content to destDir.
|
||||
// Returns a slice containing the full path of the extracted files.
|
||||
func ExtractTarGz(fileName, destDir string) ([]string, error) {
|
||||
var files []string
|
||||
|
||||
gzipStream, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open file %q: %w", fileName, err)
|
||||
}
|
||||
|
||||
uncompressedStream, err := gzip.NewReader(gzipStream)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tarReader := tar.NewReader(uncompressedStream)
|
||||
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
return nil, fmt.Errorf("unexepected dir inside the archive, expected to find only files without any tree structure")
|
||||
case tar.TypeReg, tar.TypeSymlink:
|
||||
f := filepath.Join(destDir, filepath.Clean(header.Name))
|
||||
if !strings.HasPrefix(f, filepath.Clean(destDir)+string(os.PathSeparator)) {
|
||||
return nil, fmt.Errorf("illegal file path: %q", f)
|
||||
}
|
||||
outFile, err := os.Create(filepath.Clean(f))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = copyInChunks(outFile, tarReader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = outFile.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files = append(files, f)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("extractTarGz: uknown type: %b in %s", header.Typeflag, header.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func copyInChunks(dst io.Writer, src io.Reader) error {
|
||||
for {
|
||||
_, err := io.CopyN(dst, src, 1024)
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package distribution_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestDistribution(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Distribution Suite")
|
||||
}
|
|
@ -1,190 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package distribution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/common"
|
||||
|
||||
"github.com/falcosecurity/falcoctl/pkg/index/index"
|
||||
falcoctloci "github.com/falcosecurity/falcoctl/pkg/oci"
|
||||
"github.com/falcosecurity/falcoctl/pkg/oci/authn"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/oci"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/registry"
|
||||
"oras.land/oras-go/v2/errdef"
|
||||
"oras.land/oras-go/v2/registry/remote"
|
||||
"oras.land/oras-go/v2/registry/remote/auth"
|
||||
)
|
||||
|
||||
// Define our conventions.
|
||||
const (
|
||||
GHOrg = "falcosecurity"
|
||||
)
|
||||
|
||||
func PluginToIndexEntry(p registry.Plugin, registry, repo string) *index.Entry {
|
||||
return &index.Entry{
|
||||
Name: p.Name,
|
||||
Type: string(falcoctloci.Plugin),
|
||||
Registry: registry,
|
||||
Signature: p.Signature,
|
||||
Repository: repo,
|
||||
Description: p.Description,
|
||||
Home: p.URL,
|
||||
Keywords: appendIfNotPresent(p.Keywords, p.Name),
|
||||
License: p.License,
|
||||
Maintainers: p.Maintainers,
|
||||
Sources: []string{p.URL},
|
||||
}
|
||||
}
|
||||
|
||||
func PluginRulesToIndexEntry(p registry.Plugin, registry, repo string) *index.Entry {
|
||||
return &index.Entry{
|
||||
Name: p.Name + common.RulesArtifactSuffix,
|
||||
Type: string(falcoctloci.Rulesfile),
|
||||
Registry: registry,
|
||||
Signature: p.Signature,
|
||||
Repository: repo,
|
||||
Description: p.Description,
|
||||
Home: p.URL,
|
||||
Keywords: appendIfNotPresent(p.Keywords, p.Name+common.RulesArtifactSuffix),
|
||||
License: p.License,
|
||||
Maintainers: p.Maintainers,
|
||||
Sources: []string{p.RulesURL},
|
||||
}
|
||||
}
|
||||
|
||||
func upsertIndex(r *registry.Registry, ociArtifacts map[string]string, indexPath string) error {
|
||||
i := index.New(GHOrg)
|
||||
|
||||
if err := i.Read(indexPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, p := range r.Plugins {
|
||||
// If the plugins is reserved than we just skip it.
|
||||
if p.Reserved {
|
||||
continue
|
||||
}
|
||||
|
||||
// We only publish falcosecurity artifacts that have been uploaded to the repo.
|
||||
if refPlugin, ok := ociArtifacts[p.Name]; ok {
|
||||
tokens := strings.Split(refPlugin, "/")
|
||||
ociRegistry := tokens[0]
|
||||
ociRepo := filepath.Join(tokens[1:]...)
|
||||
i.Upsert(PluginToIndexEntry(p, ociRegistry, ociRepo))
|
||||
}
|
||||
if refRulesfile, ok := ociArtifacts[p.Name+common.RulesArtifactSuffix]; ok {
|
||||
tokens := strings.Split(refRulesfile, "/")
|
||||
ociRegistry := tokens[0]
|
||||
ociRepo := filepath.Join(tokens[1:]...)
|
||||
i.Upsert(PluginRulesToIndexEntry(p, ociRegistry, ociRepo))
|
||||
}
|
||||
}
|
||||
|
||||
return i.Write(indexPath)
|
||||
}
|
||||
|
||||
func DoUpdateIndex(registryFile, indexFile string) error {
|
||||
var user, reg string
|
||||
var found bool
|
||||
if user, found = os.LookupEnv(oci.RegistryUser); !found {
|
||||
return fmt.Errorf("environment variable with key %q not found, please set it before running this tool", oci.RegistryUser)
|
||||
}
|
||||
|
||||
if reg, found = os.LookupEnv(oci.RegistryOCI); !found {
|
||||
return fmt.Errorf("environment variable with key %q not found, please set it before running this tool", oci.RegistryOCI)
|
||||
}
|
||||
|
||||
registryEntries, err := registry.LoadRegistryFromFile(registryFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ociEntries, err := ociRepos(registryEntries, reg, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := registryEntries.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return upsertIndex(registryEntries, ociEntries, indexFile)
|
||||
}
|
||||
|
||||
func ociRepos(registryEntries *registry.Registry, reg, user string) (map[string]string, error) {
|
||||
ociClient := authn.NewClient(authn.WithCredentials(&auth.EmptyCredential))
|
||||
ociEntries := make(map[string]string)
|
||||
|
||||
for _, entry := range registryEntries.Plugins {
|
||||
if err := ociRepo(ociEntries, ociClient, oci.PluginNamespace, reg, user, entry.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.RulesURL != "" {
|
||||
if err := ociRepo(ociEntries, ociClient, oci.RulesfileNamespace, reg, user, entry.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ociEntries, nil
|
||||
}
|
||||
|
||||
func ociRepo(ociEntries map[string]string, client remote.Client, ociRepoNamespace, reg, user, artifactName string) error {
|
||||
ref := filepath.Join(reg, user, ociRepoNamespace, artifactName)
|
||||
|
||||
if ociRepoNamespace == oci.RulesfileNamespace {
|
||||
artifactName = artifactName + common.RulesArtifactSuffix
|
||||
}
|
||||
|
||||
repo, err := remote.NewRepository(ref)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create repo for ref %q: %w", ref, err)
|
||||
}
|
||||
repo.Client = client
|
||||
|
||||
_, _, err = repo.FetchReference(context.Background(), ref+":latest")
|
||||
if err != nil && (errors.Is(err, errdef.ErrNotFound) || strings.Contains(err.Error(), "requested access to the resource is denied")) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to fetch reference for %q: %w", ref+":latest", err)
|
||||
}
|
||||
|
||||
ociEntries[artifactName] = ref
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add new item to a slice if not present.
|
||||
func appendIfNotPresent(keywords []string, kw string) []string {
|
||||
// If the keyword already exist do nothing.
|
||||
for i := range keywords {
|
||||
if keywords[i] == kw {
|
||||
return keywords
|
||||
}
|
||||
}
|
||||
|
||||
// Add the keyword
|
||||
return append(keywords, kw)
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package distribution_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/falcosecurity/falcoctl/pkg/index/index"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/distribution"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/registry"
|
||||
)
|
||||
|
||||
func TestPluginToIndexEntrySignature(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
signature := &index.Signature{
|
||||
Cosign: &index.CosignSignature{},
|
||||
}
|
||||
|
||||
expected := signature
|
||||
|
||||
p := registry.Plugin{Signature: signature}
|
||||
|
||||
entry := distribution.PluginToIndexEntry(p, "", "")
|
||||
if !reflect.DeepEqual(entry.Signature, expected) {
|
||||
t.Fatalf("Index entry signature: expected %#v, got %v", expected, entry.Signature)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginRulesToIndexEntrySignature(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
signature := &index.Signature{
|
||||
Cosign: &index.CosignSignature{},
|
||||
}
|
||||
|
||||
expected := signature
|
||||
|
||||
p := registry.Plugin{Signature: signature}
|
||||
|
||||
entry := distribution.PluginRulesToIndexEntry(p, "", "")
|
||||
if !reflect.DeepEqual(entry.Signature, expected) {
|
||||
t.Fatalf("Index entry signature: expected %#v, got %v", expected, entry.Signature)
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package distribution_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/distribution"
|
||||
)
|
||||
|
||||
const (
|
||||
indexFile = "testdata/index.yaml"
|
||||
wrongIndexFile = "testdata/wrong-index.yaml"
|
||||
registryFile = "testdata/registry.yaml"
|
||||
wrongRegistryFile = "testdata/wrong-registry.yaml"
|
||||
registryUser = "falcosecurity"
|
||||
registryName = "ghcr.io"
|
||||
)
|
||||
|
||||
var _ = Describe("Update index", func() {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
Context("with registry file", func() {
|
||||
BeforeEach(func() {
|
||||
os.Setenv("REGISTRY_USER", registryUser)
|
||||
os.Setenv("REGISTRY", registryName)
|
||||
})
|
||||
Context("with index file", func() {
|
||||
BeforeEach(func() {
|
||||
err = distribution.DoUpdateIndex(registryFile, indexFile)
|
||||
})
|
||||
It("Should not fail", func() {
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
})
|
||||
Context("without index file", func() {
|
||||
BeforeEach(func() {
|
||||
err = distribution.DoUpdateIndex(registryFile, wrongIndexFile)
|
||||
})
|
||||
It("Should fail", func() {
|
||||
Expect(err).ToNot(BeNil())
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("without registry file", func() {
|
||||
BeforeEach(func() {
|
||||
os.Setenv("REGISTRY_USER", registryUser)
|
||||
os.Setenv("REGISTRY", registryName)
|
||||
})
|
||||
Context("with index file", func() {
|
||||
BeforeEach(func() {
|
||||
err = distribution.DoUpdateIndex(wrongRegistryFile, indexFile)
|
||||
})
|
||||
It("Should fail", func() {
|
||||
Expect(err).ToNot(BeNil())
|
||||
})
|
||||
})
|
||||
Context("without index file", func() {
|
||||
BeforeEach(func() {
|
||||
err = distribution.DoUpdateIndex(wrongRegistryFile, wrongIndexFile)
|
||||
})
|
||||
It("Should fail", func() {
|
||||
Expect(err).ToNot(BeNil())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,247 +0,0 @@
|
|||
- name: application-rules
|
||||
type: rulesfile
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/rules/application-rules
|
||||
description: Application rules
|
||||
home: https://github.com/falcosecurity/rules/blob/main/rules/application_rules.yaml
|
||||
keywords:
|
||||
- application-rules
|
||||
license: apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/rules/blob/main/rules/application_rules.yaml
|
||||
- name: cloudtrail
|
||||
type: plugin
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/plugin/cloudtrail
|
||||
description: Reads Cloudtrail JSON logs from files/S3 and injects as events
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/cloudtrail
|
||||
keywords:
|
||||
- audit
|
||||
- user-activity
|
||||
- api-usage
|
||||
- aws
|
||||
- cloudtrail
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/cloudtrail
|
||||
- name: cloudtrail-rules
|
||||
type: rulesfile
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/ruleset/cloudtrail
|
||||
description: Reads Cloudtrail JSON logs from files/S3 and injects as events
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/cloudtrail
|
||||
keywords:
|
||||
- audit
|
||||
- user-activity
|
||||
- api-usage
|
||||
- aws
|
||||
- cloudtrail-rules
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/cloudtrail/rules
|
||||
- name: dummy
|
||||
type: plugin
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/plugin/dummy
|
||||
description: Reference plugin used to document interface
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/dummy
|
||||
keywords:
|
||||
- dummy
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/dummy
|
||||
- name: dummy_c
|
||||
type: plugin
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/plugin/dummy_c
|
||||
description: Like dummy, but written in C++
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/dummy_c
|
||||
keywords:
|
||||
- dummy_c
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/dummy_c
|
||||
- name: falco-rules
|
||||
type: rulesfile
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/rules/falco-rules
|
||||
description: Falco rules that are loaded by default
|
||||
home: https://github.com/falcosecurity/rules/blob/main/rules/falco_rules.yaml
|
||||
keywords:
|
||||
- falco-rules
|
||||
license: apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/rules/blob/main/rules/falco_rules.yaml
|
||||
- name: github
|
||||
type: plugin
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/plugin/github
|
||||
description: Github Webhook Events
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/github
|
||||
keywords:
|
||||
- audit
|
||||
- log-events
|
||||
- webhook
|
||||
- github-activity
|
||||
- github
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/github
|
||||
- name: github-rules
|
||||
type: rulesfile
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/ruleset/github
|
||||
description: Github Webhook Events
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/github
|
||||
keywords:
|
||||
- audit
|
||||
- log-events
|
||||
- webhook
|
||||
- github-activity
|
||||
- github
|
||||
- github-rules
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/github/rules
|
||||
- name: json
|
||||
type: plugin
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/plugin/json
|
||||
description: Extract values from any JSON payload
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/json
|
||||
keywords:
|
||||
- json-events
|
||||
- json-payload
|
||||
- extractor
|
||||
- json
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/json
|
||||
- name: k8saudit
|
||||
type: plugin
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/plugin/k8saudit
|
||||
description: Read Kubernetes Audit Events and monitor Kubernetes Clusters
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit
|
||||
keywords:
|
||||
- audit
|
||||
- audit-log
|
||||
- audit-events
|
||||
- kubernetes
|
||||
- k8saudit
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit
|
||||
- name: k8saudit-eks
|
||||
type: plugin
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/plugin/k8saudit-eks
|
||||
description: Read Kubernetes Audit Events from AWS EKS Clusters
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit-eks
|
||||
keywords:
|
||||
- audit
|
||||
- audit-log
|
||||
- audit-events
|
||||
- kubernetes
|
||||
- eks
|
||||
- aws
|
||||
- k8saudit-eks
|
||||
license: Apache-2.0
|
||||
maintainers: []
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit-eks
|
||||
- name: k8saudit-rules
|
||||
type: rulesfile
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/ruleset/k8saudit
|
||||
description: Read Kubernetes Audit Events and monitor Kubernetes Clusters
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit
|
||||
keywords:
|
||||
- audit
|
||||
- audit-log
|
||||
- audit-events
|
||||
- kubernetes
|
||||
- k8saudit-rules
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit/rules
|
||||
- name: okta
|
||||
type: plugin
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/plugin/okta
|
||||
signature:
|
||||
cosign:
|
||||
certificate-oidc-issuer: https://token.actions.githubusercontent.com
|
||||
certificate-oidc-issuer-regexp: ""
|
||||
certificate-identity: ""
|
||||
certificate-identity-regexp: https://github.com/LucaGuerra/cool-falco-ruleset/
|
||||
certificate-github-workflow: ""
|
||||
description: Okta Log Events
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/okta
|
||||
keywords:
|
||||
- audit
|
||||
- log-events
|
||||
- okta
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/okta
|
||||
- name: okta-rules
|
||||
type: rulesfile
|
||||
registry: ghcr.io
|
||||
repository: falcosecurity/plugins/ruleset/okta
|
||||
signature:
|
||||
cosign:
|
||||
certificate-oidc-issuer: https://token.actions.githubusercontent.com
|
||||
certificate-oidc-issuer-regexp: ""
|
||||
certificate-identity: ""
|
||||
certificate-identity-regexp: https://github.com/LucaGuerra/cool-falco-ruleset/
|
||||
certificate-github-workflow: ""
|
||||
description: Okta Log Events
|
||||
home: https://github.com/falcosecurity/plugins/tree/main/plugins/okta
|
||||
keywords:
|
||||
- audit
|
||||
- log-events
|
||||
- okta
|
||||
- okta-rules
|
||||
license: Apache-2.0
|
||||
maintainers:
|
||||
- email: cncf-falco-dev@lists.cncf.io
|
||||
name: The Falco Authors
|
||||
sources:
|
||||
- https://github.com/falcosecurity/plugins/tree/main/plugins/okta/rules
|
|
@ -1,271 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2023 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# The list of the data sources not allowed in plugins, since they are already
|
||||
# used in Falco.
|
||||
reserved_sources: ["syscall", "internal", "plugins"]
|
||||
|
||||
# The list of plugins officially recognized by the Falcosecurity organization.
|
||||
# Registering your plugin here is required to reserve a given name, source, or id.
|
||||
#
|
||||
# License IDs refer to the SPDX License List at https://spdx.org/licenses
|
||||
plugins:
|
||||
- name: k8saudit
|
||||
description: Read Kubernetes Audit Events and monitor Kubernetes Clusters
|
||||
authors: The Falco Authors
|
||||
contact: https://falco.org/community
|
||||
maintainers:
|
||||
- name: The Falco Authors
|
||||
email: cncf-falco-dev@lists.cncf.io
|
||||
keywords:
|
||||
- audit
|
||||
- audit-log
|
||||
- audit-events
|
||||
- kubernetes
|
||||
url: https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit
|
||||
rules_url: https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit/rules
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 1
|
||||
source: k8s_audit
|
||||
extraction:
|
||||
supported: true
|
||||
- name: cloudtrail
|
||||
description: Reads Cloudtrail JSON logs from files/S3 and injects as events
|
||||
authors: The Falco Authors
|
||||
contact: https://falco.org/community
|
||||
maintainers:
|
||||
- name: The Falco Authors
|
||||
email: cncf-falco-dev@lists.cncf.io
|
||||
keywords:
|
||||
- audit
|
||||
- user-activity
|
||||
- api-usage
|
||||
- aws
|
||||
url: https://github.com/falcosecurity/plugins/tree/main/plugins/cloudtrail
|
||||
rules_url: https://github.com/falcosecurity/plugins/tree/main/plugins/cloudtrail/rules
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 2
|
||||
source: aws_cloudtrail
|
||||
extraction:
|
||||
supported: true
|
||||
- name: json
|
||||
description: Extract values from any JSON payload
|
||||
authors: The Falco Authors
|
||||
contact: https://falco.org/community
|
||||
maintainers:
|
||||
- name: The Falco Authors
|
||||
email: cncf-falco-dev@lists.cncf.io
|
||||
keywords:
|
||||
- json-events
|
||||
- json-payload
|
||||
- extractor
|
||||
url: https://github.com/falcosecurity/plugins/tree/main/plugins/json
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
extraction:
|
||||
supported: true
|
||||
- name: dummy
|
||||
description: Reference plugin used to document interface
|
||||
authors: The Falco Authors
|
||||
contact: https://falco.org/community
|
||||
maintainers:
|
||||
- name: The Falco Authors
|
||||
email: cncf-falco-dev@lists.cncf.io
|
||||
url: https://github.com/falcosecurity/plugins/tree/main/plugins/dummy
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 3
|
||||
source: dummy
|
||||
extraction:
|
||||
supported: true
|
||||
- name: dummy_c
|
||||
description: Like dummy, but written in C++
|
||||
authors: The Falco Authors
|
||||
contact: https://falco.org/community
|
||||
maintainers:
|
||||
- name: The Falco Authors
|
||||
email: cncf-falco-dev@lists.cncf.io
|
||||
url: https://github.com/falcosecurity/plugins/tree/main/plugins/dummy_c
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 4
|
||||
source: dummy_c
|
||||
extraction:
|
||||
supported: true
|
||||
- name: docker
|
||||
description: Docker Events
|
||||
authors: Thomas Labarussias
|
||||
contact: https://github.com/Issif
|
||||
maintainers:
|
||||
- name: Thomas Labarussias
|
||||
email: issif_github@gadz.org
|
||||
keywords:
|
||||
- docker-events
|
||||
url: https://github.com/Issif/docker-plugin
|
||||
rules_url: https://github.com/Issif/docker-plugin/tree/main/rules
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 5
|
||||
source: docker
|
||||
extraction:
|
||||
supported: true
|
||||
- name: seccompagent
|
||||
description: Seccomp Agent Events
|
||||
authors: Alban Crequy
|
||||
contact: https://github.com/kinvolk/seccompagent
|
||||
url: https://github.com/kinvolk/seccompagent
|
||||
keywords:
|
||||
- seccomp
|
||||
- kinvolk
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 6
|
||||
source: seccompagent
|
||||
extraction:
|
||||
supported: true
|
||||
- name: okta
|
||||
description: Okta Log Events
|
||||
authors: The Falco Authors
|
||||
contact: https://falco.org/community
|
||||
maintainers:
|
||||
- name: The Falco Authors
|
||||
email: cncf-falco-dev@lists.cncf.io
|
||||
keywords:
|
||||
- audit
|
||||
- log-events
|
||||
- okta
|
||||
url: https://github.com/falcosecurity/plugins/tree/main/plugins/okta
|
||||
rules_url: https://github.com/falcosecurity/plugins/tree/main/plugins/okta/rules
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 7
|
||||
source: okta
|
||||
extraction:
|
||||
supported: true
|
||||
signature:
|
||||
cosign:
|
||||
certificate-oidc-issuer: https://token.actions.githubusercontent.com
|
||||
certificate-identity-regexp: https://github.com/LucaGuerra/cool-falco-ruleset/
|
||||
- name: github
|
||||
description: Github Webhook Events
|
||||
authors: The Falco Authors
|
||||
contact: https://falco.org/community
|
||||
maintainers:
|
||||
- name: The Falco Authors
|
||||
email: cncf-falco-dev@lists.cncf.io
|
||||
keywords:
|
||||
- audit
|
||||
- log-events
|
||||
- webhook
|
||||
- github-activity
|
||||
- github
|
||||
url: https://github.com/falcosecurity/plugins/tree/main/plugins/github
|
||||
rules_url: https://github.com/falcosecurity/plugins/tree/main/plugins/github/rules
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 8
|
||||
source: github
|
||||
extraction:
|
||||
supported: true
|
||||
- name: k8saudit-eks
|
||||
description: Read Kubernetes Audit Events from AWS EKS Clusters
|
||||
authors: The Falco Authors
|
||||
contact: https://falco.org/community
|
||||
url: https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit-eks
|
||||
rules_url: https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit/rules
|
||||
license: Apache-2.0
|
||||
keywords:
|
||||
- audit
|
||||
- audit-log
|
||||
- audit-events
|
||||
- kubernetes
|
||||
- eks
|
||||
- aws
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 9
|
||||
source: k8s_audit
|
||||
extraction:
|
||||
supported: true
|
||||
- name: nomad
|
||||
description: Read Hashicorp Nomad Events Stream
|
||||
authors: Alberto Llamas
|
||||
contact: https://github.com/albertollamaso/nomad-plugin/issues
|
||||
maintainers:
|
||||
- name: Alberto Llamas
|
||||
keywords:
|
||||
- audit
|
||||
- audit-events
|
||||
- nomad
|
||||
url: https://github.com/albertollamaso/nomad-plugin/tree/main
|
||||
rules_url: https://github.com/albertollamaso/nomad-plugin/tree/main/rules
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 10
|
||||
source: nomad
|
||||
extraction:
|
||||
supported: true
|
||||
- name: dnscollector
|
||||
description: DNS Collector Events
|
||||
authors: Daniel Moloney
|
||||
contact: https://github.com/SysdigDan/dnscollector-falco-plugin/issues
|
||||
maintainers:
|
||||
- name: Daniel Moloney
|
||||
keywords:
|
||||
- audit
|
||||
- log-events
|
||||
- dns
|
||||
url: https://github.com/SysdigDan/dnscollector-falco-plugin
|
||||
rules_url: https://github.com/SysdigDan/dnscollector-falco-plugin/tree/master/rules
|
||||
license: Apache-2.0
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 11
|
||||
source: dnscollector
|
||||
extraction:
|
||||
supported: true
|
||||
- name: test
|
||||
description: This ID is reserved for source plugin development. Any plugin author can use this ID, but authors can expect events from other developers with this ID. After development is complete, the author should request an actual ID
|
||||
reserved: true
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 999
|
||||
source: test
|
|
@ -1,128 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/falcosecurity/plugin-sdk-go/pkg/loader"
|
||||
"github.com/falcosecurity/plugin-sdk-go/pkg/sdk/plugins"
|
||||
|
||||
"github.com/falcosecurity/falcoctl/pkg/oci"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/common"
|
||||
)
|
||||
|
||||
// rulesFileConfig generates the artifact configuration for a rulesfile starting form the tar.gz archive,
|
||||
// its name and version.
|
||||
func rulesfileConfig(name, version, filePath string) (*oci.ArtifactConfig, error) {
|
||||
// Create temp dir.
|
||||
tmpDir, err := os.MkdirTemp("", "registry-oci-")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create temporary dir while preparing to extract rulesfile %q: %v", filePath, err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
files, err := common.ExtractTarGz(filePath, tmpDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg := &oci.ArtifactConfig{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Dependencies: nil,
|
||||
Requirements: nil,
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
// Get the requirements for the given file.
|
||||
req, err := rulesfileRequirement(file)
|
||||
if err != nil && !errors.Is(err, ErrReqNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
// If found add it to the requirements list.
|
||||
if err == nil {
|
||||
_ = cfg.SetRequirement(req.Name, req.Version)
|
||||
}
|
||||
|
||||
deps, err := rulesfileDependencies(file)
|
||||
if err != nil && !errors.Is(err, ErrDepNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
// If found add it to the dependencies list.
|
||||
if err == nil {
|
||||
for _, d := range deps {
|
||||
_ = cfg.SetDependency(d.Name, d.Version, d.Alternatives)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Dependencies == nil || cfg.Requirements == nil {
|
||||
return nil, fmt.Errorf("no dependencies or requirements found for rulesfile %q", filePath)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func pluginConfig(name, version string, pluginInfo *plugins.Info) (*oci.ArtifactConfig, error) {
|
||||
// Check that the name we got from the registry.yaml is the same as the embedded one in the plugin at build time.
|
||||
if name != pluginInfo.Name {
|
||||
return nil, fmt.Errorf("mismatch between name in registry.yaml (%q) and name found in plugin shared object (%q)", name, pluginInfo.Name)
|
||||
}
|
||||
|
||||
cfg := &oci.ArtifactConfig{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Dependencies: nil,
|
||||
Requirements: nil,
|
||||
}
|
||||
|
||||
_ = cfg.SetRequirement(common.PluginAPIVersion, pluginInfo.RequiredAPIVersion)
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func pluginInfo(filePath string) (*plugins.Info, error) {
|
||||
// Create temp dir.
|
||||
tmpDir, err := os.MkdirTemp("", "registry-oci-")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create temporary dir while preparing to extract plugin %q: %v", filePath, err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
files, err := common.ExtractTarGz(filePath, tmpDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
// skip files that are not a shared library such as README files.
|
||||
if !strings.HasSuffix(file, ".so") {
|
||||
continue
|
||||
}
|
||||
// Get the plugin info.
|
||||
plugin, err := loader.NewPlugin(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open plugin %q: %w", file, err)
|
||||
}
|
||||
return plugin.Info(), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no plugin found in archive %q", filePath)
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2022 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
const (
|
||||
PluginNamespace = "plugins/plugin"
|
||||
RulesfileNamespace = "plugins/ruleset"
|
||||
RegistryToken = "REGISTRY_TOKEN"
|
||||
RegistryUser = "REGISTRY_USER"
|
||||
RegistryOCI = "REGISTRY"
|
||||
RepoGithub = "REPO_GITHUB"
|
||||
FalcoAuthors = "The Falco Authors"
|
||||
PluginsRepo = "https://github.com/falcosecurity/plugins"
|
||||
archiveSuffix = ".tar.gz"
|
||||
amd64Platform = "linux/amd64"
|
||||
arm64Platform = "linux/arm64"
|
||||
)
|
|
@ -1,83 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/falcosecurity/falcoctl/pkg/oci"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const depsKey = "- required_plugin_versions"
|
||||
|
||||
// ErrDepNotFound error when the dependencies are not found in the rulesfile.
|
||||
var ErrDepNotFound = errors.New("dependencies not found")
|
||||
|
||||
// rulesfileDependencies given a rulesfile in yaml format it scans it nad extracts its dependencies.
|
||||
func rulesfileDependencies(fileName string) ([]oci.ArtifactDependency, error) {
|
||||
var start bool
|
||||
var buf []byte
|
||||
var deps []oci.ArtifactDependency
|
||||
|
||||
// Open the file.
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open file %q: %v", fileName, file)
|
||||
}
|
||||
|
||||
// Prepare the file to be read line by line.
|
||||
fileScanner := bufio.NewScanner(file)
|
||||
fileScanner.Split(bufio.ScanLines)
|
||||
|
||||
// Is appended to each line when inserted in the buffer.
|
||||
newLine := []byte("\n")
|
||||
|
||||
// Falco rulesfiles are a list of dictionaries. We only want the "required plugin versions" by the ruleset. We do
|
||||
// not want to load all the file in memory, so we scan it line by line. When we reach the interested section we save
|
||||
// each line in a buffer, and after that we unmarshal it to a proper data structure.
|
||||
for fileScanner.Scan() {
|
||||
// If we have already found the section of interest, and we get a new item of the list then we stop.
|
||||
if start {
|
||||
if strings.HasPrefix(fileScanner.Text(), "-") {
|
||||
break
|
||||
} else {
|
||||
buf = append(buf, fileScanner.Bytes()...)
|
||||
buf = append(buf, newLine...)
|
||||
}
|
||||
} else {
|
||||
if strings.HasPrefix(fileScanner.Text(), depsKey) {
|
||||
start = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !start {
|
||||
return nil, fmt.Errorf("dependencies for rulesfile %q: %w", fileName, ErrDepNotFound)
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(buf, &deps); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal the required plugins versions: %w", err)
|
||||
}
|
||||
|
||||
return deps, nil
|
||||
}
|
|
@ -1,423 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/falcosecurity/plugin-sdk-go/pkg/sdk/plugins"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/common"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/falcosecurity/falcoctl/pkg/oci"
|
||||
"github.com/falcosecurity/falcoctl/pkg/oci/authn"
|
||||
ocipusher "github.com/falcosecurity/falcoctl/pkg/oci/pusher"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/registry"
|
||||
"k8s.io/klog/v2"
|
||||
"oras.land/oras-go/v2/registry/remote"
|
||||
"oras.land/oras-go/v2/registry/remote/auth"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
// registryToken authentication token for the OCI registry.
|
||||
registryToken string
|
||||
// registryUser user used to interact with the OCI registry.
|
||||
registryUser string
|
||||
// registryHost hostname of the OCI registry.
|
||||
registryHost string
|
||||
// pluginsRepo the Ref of the git repository associated with the OCI artifacts.
|
||||
pluginsRepo string
|
||||
}
|
||||
|
||||
func lookupConfig() (*config, error) {
|
||||
var found bool
|
||||
cfg := &config{}
|
||||
|
||||
if cfg.registryToken, found = os.LookupEnv(RegistryToken); !found {
|
||||
return nil, fmt.Errorf("environment variable with key %q not found, please set it before running this tool", RegistryToken)
|
||||
}
|
||||
|
||||
if cfg.registryUser, found = os.LookupEnv(RegistryUser); !found {
|
||||
return nil, fmt.Errorf("environment variable with key %q not found, please set it before running this tool", RegistryUser)
|
||||
}
|
||||
|
||||
if cfg.registryHost, found = os.LookupEnv(RegistryOCI); !found {
|
||||
return nil, fmt.Errorf("environment variable with key %q not found, please set it before running this tool", RegistryOCI)
|
||||
}
|
||||
|
||||
if cfg.pluginsRepo, found = os.LookupEnv(RepoGithub); !found {
|
||||
return nil, fmt.Errorf("environment variable with key %q not found, please set it before running this tool", RepoGithub)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// refFromPluginEntry returns an OCI reference for a plugin entry in the registry.yaml file.
|
||||
func refFromPluginEntry(cfg *config, plugin *registry.Plugin, rulesFile bool) string {
|
||||
var namespace string
|
||||
|
||||
// If the RulesURL field is set then the artifact is a rulesfile, otherwise a plugin.
|
||||
if rulesFile {
|
||||
namespace = RulesfileNamespace
|
||||
} else {
|
||||
namespace = PluginNamespace
|
||||
}
|
||||
|
||||
// Build and return the artifact reference.
|
||||
return filepath.Join(cfg.registryHost, cfg.registryUser, namespace, plugin.Name)
|
||||
}
|
||||
|
||||
func currentPlatform() string {
|
||||
return fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// DoUpdateOCIRegistry publishes new plugins with related rules to be released.
|
||||
// For each plugin in the registry index, it looks for new versions, since the latest version fetched from the remote OCI
|
||||
// repository, as tags on the local Git repository.
|
||||
// For each new version, it downloads the related plugin and rule set from the Falco distribution and updates the OCI
|
||||
// repository accordingly.
|
||||
func DoUpdateOCIRegistry(ctx context.Context, registryFile, pluginsAMD4, pluginsARM64, rulesfiles, devTag string) ([]registry.ArtifactPushMetadata, error) {
|
||||
var (
|
||||
cfg *config
|
||||
err error
|
||||
)
|
||||
|
||||
// Load the configuration from env variables.
|
||||
if cfg, err = lookupConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cred := &auth.Credential{
|
||||
Username: cfg.registryUser,
|
||||
Password: cfg.registryToken,
|
||||
}
|
||||
|
||||
ociClient := authn.NewClient(authn.WithCredentials(cred))
|
||||
|
||||
reg, err := registry.LoadRegistryFromFile(registryFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("an error occurred while loading registry entries from file %q: %v", registryFile, err)
|
||||
}
|
||||
|
||||
artifacts := []registry.ArtifactPushMetadata{}
|
||||
|
||||
// For each plugin in the registry index, look for new ones to be released, and publish them.
|
||||
for _, plugin := range reg.Plugins {
|
||||
pa, ra, err := handleArtifact(ctx, cfg, &plugin, ociClient, pluginsAMD4, pluginsARM64, rulesfiles, devTag)
|
||||
if err != nil {
|
||||
return artifacts, err
|
||||
}
|
||||
|
||||
artifacts = append(artifacts, pa...)
|
||||
artifacts = append(artifacts, ra...)
|
||||
|
||||
// Clean up
|
||||
if err := os.RemoveAll(plugin.Name); err != nil {
|
||||
return artifacts, fmt.Errorf("unable to remove folder %q: %v", plugin.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return artifacts, nil
|
||||
}
|
||||
|
||||
func tagsFromVersion(version *semver.Version) []string {
|
||||
var tags []string
|
||||
|
||||
// If we are not handling a release candidate then add floating tags.
|
||||
if len(version.Pre) == 0 {
|
||||
majorVer := fmt.Sprintf("%d", version.Major)
|
||||
minorVer := fmt.Sprintf("%d.%d", version.Major, version.Minor)
|
||||
fullVer := version.String()
|
||||
|
||||
tags = append(tags, "latest", majorVer, minorVer, fullVer)
|
||||
} else {
|
||||
tags = append(tags, version.String())
|
||||
}
|
||||
|
||||
return tags
|
||||
}
|
||||
|
||||
// handleArtifact it pushes artifacts related to a given plugin in the registry.yaml file.
|
||||
// It could happen that for a given plugin no artifacts such as builds and rulesets are available.
|
||||
// Consider the case when we release a single plugin.
|
||||
func handleArtifact(ctx context.Context, cfg *config, plugin *registry.Plugin, ociClient remote.Client,
|
||||
pluginsAMD64, pluginsARM64, rulesfiles, devTag string) ([]registry.ArtifactPushMetadata, []registry.ArtifactPushMetadata, error) {
|
||||
// Filter out plugins that are not owned by falcosecurity.
|
||||
if !strings.HasPrefix(plugin.URL, PluginsRepo) {
|
||||
sepString := strings.Repeat("#", 15)
|
||||
klog.Info("%s %s %s", sepString, plugin.Name, sepString)
|
||||
klog.Infof("skipping plugin %q with authors %q: it is not maintained by %q",
|
||||
plugin.Name, plugin.Authors, FalcoAuthors)
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
// Handle the plugin.
|
||||
newPluginArtifacts, err := handlePlugin(ctx, cfg, plugin, ociClient, pluginsAMD64, pluginsARM64, devTag)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Handle the rules.
|
||||
newRuleArtifacts := []registry.ArtifactPushMetadata{}
|
||||
|
||||
if plugin.RulesURL != "" {
|
||||
newRuleArtifacts, err = handleRule(ctx, cfg, plugin, ociClient, rulesfiles, devTag)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return newPluginArtifacts, newRuleArtifacts, nil
|
||||
}
|
||||
|
||||
// handlePlugin for a given plugin it checks if there exists build artifacts in the given folders, and
|
||||
// if found packs them as an OCI artifact and pushes them to the registry.
|
||||
func handlePlugin(ctx context.Context, cfg *config, plugin *registry.Plugin, ociClient remote.Client,
|
||||
pluginsAMD64, pluginsARM64 string, devTag string) ([]registry.ArtifactPushMetadata, error) {
|
||||
var configLayer *oci.ArtifactConfig
|
||||
var err error
|
||||
var filepaths, platforms, tags []string
|
||||
var version string
|
||||
var infoP *plugins.Info
|
||||
|
||||
// Build the reference for the artifact.
|
||||
ref := refFromPluginEntry(cfg, plugin, false)
|
||||
|
||||
// Metadata of the plugins OCI artifacts push.
|
||||
metadata := []registry.ArtifactPushMetadata{}
|
||||
|
||||
// Get the name of the build object for the amd64 architecture.
|
||||
amd64Build, err := buildName(plugin.Name, pluginsAMD64, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if amd64Build != "" {
|
||||
if infoP, err = pluginInfo(filepath.Join(pluginsAMD64, amd64Build)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check that the plugin has the same name as the one we got from the registry.yaml.
|
||||
// If not, we skip it. It could happen that plugins share the same prefix, example k8saudit, k8saudit-gke.
|
||||
if infoP.Name != plugin.Name {
|
||||
// buildName func returned a wrong path starting from the plugin name found in registry.yaml.
|
||||
klog.Warningf("skipping plugin since there is a mismatch in plugin name (%q) and plugin info name(%q)", plugin.Name, infoP.Name)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
filepaths = append(filepaths, filepath.Join(pluginsAMD64, amd64Build))
|
||||
platforms = append(platforms, amd64Platform)
|
||||
}
|
||||
|
||||
// Get the name of the build object for the arm64 architecture.
|
||||
arm64Build, err := buildName(plugin.Name, pluginsARM64, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if arm64Build != "" {
|
||||
filepaths = append(filepaths, filepath.Join(pluginsARM64, arm64Build))
|
||||
platforms = append(platforms, arm64Platform)
|
||||
}
|
||||
|
||||
if arm64Build == "" && amd64Build == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sepString := strings.Repeat("#", 15)
|
||||
klog.Infof("%s %s %s", sepString, plugin.Name, sepString)
|
||||
|
||||
// Extract version from build object.
|
||||
klog.Infof("generating plugin's config layer")
|
||||
|
||||
version, tags, err = versionAndTags(plugin.Name, filepath.Base(filepaths[0]), devTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if infoP == nil {
|
||||
klog.Warningf("no config layer generated for plugin %q: the plugins has not been build for the current platform %q", plugin.Name, currentPlatform())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
configLayer, err = pluginConfig(plugin.Name, version, infoP)
|
||||
if err != nil {
|
||||
klog.Errorf("unable to generate config file: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
klog.Infof("pushing plugin to remote repo with ref %q and tags %q", ref, tags)
|
||||
pusher := ocipusher.NewPusher(ociClient, false, nil)
|
||||
res, err := pusher.Push(ctx, oci.Plugin, ref,
|
||||
ocipusher.WithTags(tags...),
|
||||
ocipusher.WithFilepathsAndPlatforms(filepaths, platforms),
|
||||
ocipusher.WithArtifactConfig(*configLayer),
|
||||
ocipusher.WithAnnotationSource(cfg.pluginsRepo))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("an error occurred while pushing plugin %q: %w", plugin.Name, err)
|
||||
}
|
||||
if res != nil {
|
||||
metadata = append(metadata, registry.ArtifactPushMetadata{
|
||||
registry.RepositoryMetadata{
|
||||
Ref: ref,
|
||||
},
|
||||
registry.ArtifactMetadata{
|
||||
Digest: res.RootDigest,
|
||||
Tags: tags,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return metadata, nil
|
||||
}
|
||||
|
||||
// handleRule for a given plugin it checks if there exists rulesfiles in the given folder, and
|
||||
// if found packs them as an OCI artifact and pushes it to the registry.
|
||||
func handleRule(ctx context.Context, cfg *config, plugin *registry.Plugin,
|
||||
ociClient remote.Client, rulesfiles, devTag string) ([]registry.ArtifactPushMetadata, error) {
|
||||
var err error
|
||||
var filepaths, tags []string
|
||||
var version string
|
||||
|
||||
// Build the reference for the artifact.
|
||||
ref := refFromPluginEntry(cfg, plugin, true)
|
||||
|
||||
// Metadata of the plugins OCI artifacts push.
|
||||
metadata := []registry.ArtifactPushMetadata{}
|
||||
|
||||
// Get the name of the build object for the amd64 architecture.
|
||||
rulesfileBuild, err := buildName(plugin.Name, rulesfiles, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rulesfileBuild != "" {
|
||||
filepaths = append(filepaths, filepath.Join(rulesfiles, rulesfileBuild))
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sepString := strings.Repeat("#", 15)
|
||||
klog.Infof("%s %s %s", sepString, rulesfileNameFromPlugin(plugin.Name), sepString)
|
||||
|
||||
klog.Infof("generating rulesfile's config layer")
|
||||
|
||||
version, tags, err = versionAndTags(plugin.Name, filepath.Base(filepaths[0]), devTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configLayer, err := rulesfileConfig(rulesfileNameFromPlugin(plugin.Name), version, filepaths[0])
|
||||
if err != nil {
|
||||
klog.Errorf("unable to generate config file: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
klog.Infof("pushing rulesfile to remote repo with ref %q and tags %q", ref, tags)
|
||||
pusher := ocipusher.NewPusher(ociClient, false, nil)
|
||||
res, err := pusher.Push(ctx, oci.Rulesfile, ref,
|
||||
ocipusher.WithTags(tags...),
|
||||
ocipusher.WithFilepaths(filepaths),
|
||||
ocipusher.WithArtifactConfig(*configLayer),
|
||||
ocipusher.WithAnnotationSource(cfg.pluginsRepo))
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("an error occurred while pushing rulesfile %q: %w", plugin.Name, err)
|
||||
}
|
||||
if res != nil {
|
||||
metadata = append(metadata, registry.ArtifactPushMetadata{
|
||||
registry.RepositoryMetadata{
|
||||
Ref: ref,
|
||||
},
|
||||
registry.ArtifactMetadata{
|
||||
Digest: res.RootDigest,
|
||||
Tags: tags,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return metadata, nil
|
||||
}
|
||||
|
||||
func rulesfileNameFromPlugin(name string) string {
|
||||
return fmt.Sprintf("%s%s", name, common.RulesArtifactSuffix)
|
||||
}
|
||||
|
||||
// buildName returns the name of the build object for a given object name.
|
||||
// It searches in the given folder if build artifact exists that has the same
|
||||
// prefix as the object. If we are searching for a rulesfiles object then, the
|
||||
// rulefiles variable needs to be set to true.
|
||||
func buildName(objName, dirPath string, rulesfile bool) (string, error) {
|
||||
if dirPath == "" {
|
||||
return "", nil
|
||||
}
|
||||
// Get the entries
|
||||
entries, err := os.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to get build object for %q: %w", objName, err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
name := entry.Name()
|
||||
if rulesfile {
|
||||
if strings.HasPrefix(name, objName+"-rules") {
|
||||
return name, nil
|
||||
}
|
||||
} else {
|
||||
if strings.HasPrefix(name, objName) && !strings.Contains(name, "rules") {
|
||||
return name, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func versionAndTags(pluginName, buildName, devTag string) (string, []string, error) {
|
||||
var version string
|
||||
var tags []string
|
||||
var err error
|
||||
|
||||
if strings.Contains(buildName, "-rules") {
|
||||
version = strings.TrimPrefix(buildName, pluginName+"-rules-")
|
||||
version = strings.TrimSuffix(version, archiveSuffix)
|
||||
} else {
|
||||
regexPattern := `\b-linux\S*`
|
||||
regex := regexp.MustCompile(regexPattern)
|
||||
// Replace all substrings starting with "linux" with an empty string
|
||||
version = regex.ReplaceAllString(buildName, "")
|
||||
version = strings.TrimPrefix(version, pluginName+"-")
|
||||
}
|
||||
|
||||
if devTag != "" {
|
||||
return version, append(tags, devTag), nil
|
||||
}
|
||||
|
||||
// If not a dev version, we expect to but be semver compatible.
|
||||
semVer, err := semver.Parse(version)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("unable to parse version for %q: %w", buildName, err)
|
||||
}
|
||||
return version, tagsFromVersion(&semVer), nil
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
const (
|
||||
samplePluginRepoRef = "ghcr.io/falcosecurity/plugins/plugins/k8saudit"
|
||||
sampleDigest = "sha256:454b5d97ecbb71c8b605af2028f12fc2c792e363b150b1aeeb773c802699d647"
|
||||
samplePluginTag = "1.0.0"
|
||||
)
|
||||
|
||||
func TestOCI(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "OCI Suite")
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/registry"
|
||||
)
|
||||
|
||||
func PrintUpdateStatus(newArtifacts registry.ArtifactsPushStatus, output io.Writer) error {
|
||||
bytes, err := json.Marshal(newArtifacts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error marshaling oci registry push metadata")
|
||||
}
|
||||
output.Write(bytes)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/internal/options"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/oci"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/registry"
|
||||
)
|
||||
|
||||
var _ = Describe("Update OCI registry", func() {
|
||||
var (
|
||||
out *bytes.Buffer
|
||||
status registry.ArtifactsPushStatus
|
||||
opts *options.CommonOptions
|
||||
err error
|
||||
)
|
||||
|
||||
Context("Print update result", func() {
|
||||
BeforeEach(func() {
|
||||
out = new(bytes.Buffer)
|
||||
opts = options.NewCommonOptions(options.WithOutput(out))
|
||||
})
|
||||
|
||||
When("at least one artifact has been pushed to the OCI registry", func() {
|
||||
BeforeEach(func() {
|
||||
status = registry.ArtifactsPushStatus{
|
||||
{
|
||||
Repository: registry.RepositoryMetadata{
|
||||
Ref: samplePluginRepoRef,
|
||||
},
|
||||
Artifact: registry.ArtifactMetadata{
|
||||
Digest: sampleDigest,
|
||||
Tags: []string{samplePluginTag}},
|
||||
},
|
||||
}
|
||||
err = oci.PrintUpdateStatus(status, opts.Output)
|
||||
})
|
||||
|
||||
It("should not fail", func() {
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
It("output should not be empty", func() {
|
||||
Expect(out.String()).ToNot(BeEmpty())
|
||||
})
|
||||
It("output should contain a valid JSON", func() {
|
||||
status = registry.ArtifactsPushStatus{}
|
||||
err := json.Unmarshal(out.Bytes(), &status)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
When("no artifacts have been pushed to the OCI registry", func() {
|
||||
BeforeEach(func() {
|
||||
status = registry.ArtifactsPushStatus{}
|
||||
err = oci.PrintUpdateStatus(status, opts.Output)
|
||||
})
|
||||
|
||||
It("should not fail", func() {
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
It("output should not be empty", func() {
|
||||
Expect(out.String()).ToNot(BeEmpty())
|
||||
})
|
||||
It("output should contain a valid JSON", func() {
|
||||
status = registry.ArtifactsPushStatus{}
|
||||
err := json.Unmarshal(out.Bytes(), &status)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,88 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/falcosecurity/falcoctl/pkg/oci"
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/common"
|
||||
)
|
||||
|
||||
const (
|
||||
rulesEngineAnchor = "- required_engine_version"
|
||||
)
|
||||
|
||||
// ErrReqNotFound error when the requirements are not found in the rulesfile.
|
||||
var ErrReqNotFound = errors.New("requirements not found")
|
||||
|
||||
// rulesfileRequirement given a rulesfile in yaml format it scans it and extracts its requirements.
|
||||
func rulesfileRequirement(filePath string) (*oci.ArtifactRequirement, error) {
|
||||
var requirement string
|
||||
// Open the file.
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open file %q: %v", filePath, file)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
// Prepare the file to be read line by line.
|
||||
fileScanner := bufio.NewScanner(file)
|
||||
fileScanner.Split(bufio.ScanLines)
|
||||
|
||||
for fileScanner.Scan() {
|
||||
if strings.HasPrefix(fileScanner.Text(), rulesEngineAnchor) {
|
||||
requirement = fileScanner.Text()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if requirement == "" {
|
||||
return nil, fmt.Errorf("requirements for rulesfile %q: %w", filePath, ErrReqNotFound)
|
||||
}
|
||||
|
||||
// Split the requirement and parse the version to semVer.
|
||||
// In case the requirement was expressed as a numeric value,
|
||||
// we convert it to semver and treat it as minor version.
|
||||
tokens := strings.Split(fileScanner.Text(), ":")
|
||||
version := strings.TrimSpace(tokens[1])
|
||||
reqVer, err := semver.Parse(version)
|
||||
if err != nil {
|
||||
minor, err := strconv.ParseUint(version, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse requirement %q: expected a numeric value or a valid semver string", version)
|
||||
}
|
||||
reqVer = semver.Version{
|
||||
Major: 0,
|
||||
Minor: minor,
|
||||
Patch: 0,
|
||||
}
|
||||
}
|
||||
|
||||
return &oci.ArtifactRequirement{
|
||||
Name: common.EngineVersionKey,
|
||||
Version: reqVer.String(),
|
||||
}, nil
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2024 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRulesfileRequirement(t *testing.T) {
|
||||
req, err := rulesfileRequirement("testdata/rules-failed-req.yaml")
|
||||
assert.Error(t, err)
|
||||
|
||||
req, err = rulesfileRequirement("testdata/rules-numeric-req.yaml")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "0.15.0", req.Version)
|
||||
assert.Equal(t, "engine_version_semver", req.Name)
|
||||
|
||||
req, err = rulesfileRequirement("testdata/rules-semver-req.yaml")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "0.31.0", req.Version)
|
||||
assert.Equal(t, "engine_version_semver", req.Name)
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
- required_engine_version: test
|
|
@ -1 +0,0 @@
|
|||
- required_engine_version: 15
|
|
@ -1 +0,0 @@
|
|||
- required_engine_version: 0.31.0
|
|
@ -1,78 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type encoder interface {
|
||||
Encode(io.Writer) error
|
||||
}
|
||||
|
||||
// Encode writes the content to a io.Writer
|
||||
func (r *SourcingCapability) Encode(w io.Writer) error {
|
||||
return yaml.NewEncoder(w).Encode(r)
|
||||
}
|
||||
|
||||
// Encode writes the content to a io.Writer
|
||||
func (r *ExtractionCapability) Encode(w io.Writer) error {
|
||||
return yaml.NewEncoder(w).Encode(r)
|
||||
}
|
||||
|
||||
// Encode writes the content to a io.Writer
|
||||
func (r *Capabilities) Encode(w io.Writer) error {
|
||||
return yaml.NewEncoder(w).Encode(r)
|
||||
}
|
||||
|
||||
// Encode writes the content to a io.Writer
|
||||
func (r *Plugin) Encode(w io.Writer) error {
|
||||
return yaml.NewEncoder(w).Encode(r)
|
||||
}
|
||||
|
||||
// Encode writes the content to a io.Writer
|
||||
func (r *Registry) Encode(w io.Writer) error {
|
||||
return yaml.NewEncoder(w).Encode(r)
|
||||
}
|
||||
|
||||
// Decode fills the structure by reading from a io.Reader
|
||||
func (r *SourcingCapability) Decode(w io.Reader) error {
|
||||
return yaml.NewDecoder(w).Decode(r)
|
||||
}
|
||||
|
||||
// Decode fills the structure by reading from a io.Reader
|
||||
func (r *ExtractionCapability) Decode(w io.Reader) error {
|
||||
return yaml.NewDecoder(w).Decode(r)
|
||||
}
|
||||
|
||||
// Decode fills the structure by reading from a io.Reader
|
||||
func (r *Capabilities) Decode(w io.Reader) error {
|
||||
return yaml.NewDecoder(w).Decode(r)
|
||||
}
|
||||
|
||||
// Decode fills the structure by reading from a io.Reader
|
||||
func (r *Plugin) Decode(w io.Reader) error {
|
||||
return yaml.NewDecoder(w).Decode(r)
|
||||
}
|
||||
|
||||
// Decode fills the structure by reading from a io.Reader
|
||||
func (r *Registry) Decode(w io.Reader) error {
|
||||
return yaml.NewDecoder(w).Decode(r)
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// LoadRegistryFromFile loads the registry from a file on disk.
|
||||
func LoadRegistryFromFile(fname string) (*Registry, error) {
|
||||
file, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
return load(file)
|
||||
}
|
||||
|
||||
// load reads from a io.Reader and uses the content to populate and
|
||||
// return a new instance of Registry
|
||||
func load(r io.Reader) (*Registry, error) {
|
||||
registry := &Registry{}
|
||||
return registry, registry.Decode(r)
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
func encodeString(r encoder) string {
|
||||
buf := bytes.Buffer{}
|
||||
err := r.Encode(&buf)
|
||||
if err != nil {
|
||||
return "string encoding error: " + err.Error()
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface
|
||||
func (r *SourcingCapability) String() string {
|
||||
return encodeString(r)
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface
|
||||
func (r *ExtractionCapability) String() string {
|
||||
return encodeString(r)
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface
|
||||
func (r *Capabilities) String() string {
|
||||
return encodeString(r)
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface
|
||||
func (r *Plugin) String() string {
|
||||
return encodeString(r)
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface
|
||||
func (r *Registry) String() string {
|
||||
return encodeString(r)
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"github.com/falcosecurity/falcoctl/pkg/index/index"
|
||||
)
|
||||
|
||||
// MaxPublicID represents the max allowed value for plublic plugin IDs,
|
||||
// see https://github.com/falcosecurity/plugins/blob/main/docs/plugin-ids.md
|
||||
const MaxPublicID = 1<<30 - 1 // 1073741823 is the public block upper limit
|
||||
|
||||
type SourcingCapability struct {
|
||||
Supported bool `yaml:"supported"`
|
||||
ID uint `yaml:"id"`
|
||||
Source string `yaml:"source"`
|
||||
}
|
||||
|
||||
type ExtractionCapability struct {
|
||||
Supported bool `yaml:"supported"`
|
||||
Sources []string `yaml:"sources"`
|
||||
}
|
||||
|
||||
type Capabilities struct {
|
||||
Sourcing SourcingCapability `yaml:"sourcing"`
|
||||
Extraction ExtractionCapability `yaml:"extraction"`
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
Name string `yaml:"name"`
|
||||
Description string `yaml:"description"`
|
||||
Authors string `yaml:"authors"`
|
||||
Contact string `yaml:"contact"`
|
||||
Maintainers []struct {
|
||||
Email string `yaml:"email"`
|
||||
Name string `yaml:"name"`
|
||||
} `yaml:"maintainers"`
|
||||
Keywords []string `yaml:"keywords"`
|
||||
URL string `yaml:"url"`
|
||||
RulesURL string `yaml:"rules_url"`
|
||||
License string `yaml:"license"`
|
||||
Reserved bool `yaml:"reserved"`
|
||||
Capabilities Capabilities `yaml:"capabilities"`
|
||||
Signature *index.Signature `yaml:"signature,omitempty"`
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
Plugins []Plugin `yaml:"plugins"`
|
||||
ReservedSources []string `yaml:"reserved_sources"`
|
||||
}
|
||||
|
||||
type ArtifactsPushStatus []ArtifactPushMetadata
|
||||
|
||||
// ArtifactPushMetadata represents metadata of a push of an OCI Artifact to
|
||||
// an OCI repository.
|
||||
type ArtifactPushMetadata struct {
|
||||
Repository RepositoryMetadata `json:"repository"`
|
||||
Artifact ArtifactMetadata `json:"artifact"`
|
||||
}
|
||||
|
||||
type ArtifactMetadata struct {
|
||||
Digest string `json:"digest"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
type RepositoryMetadata struct {
|
||||
Ref string `json:"ref"`
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
rgxName = regexp.MustCompile(`^[a-z]+[a-z0-9-_]*$`)
|
||||
rgxSource = regexp.MustCompile(`^[a-z]+[a-z0-9_]*$`)
|
||||
)
|
||||
|
||||
func (s *SourcingCapability) validate(usedIDs map[uint]bool, forbiddenSources map[string]bool) error {
|
||||
if s.Supported {
|
||||
if s.ID > MaxPublicID {
|
||||
return fmt.Errorf("source ID outside the allowed range (%d): '%d'", MaxPublicID, s.ID)
|
||||
}
|
||||
if _, ok := usedIDs[s.ID]; ok {
|
||||
return fmt.Errorf("source ID is not unique: '%d'", s.ID)
|
||||
}
|
||||
// ID=0 is a special case and we don't want to define a source name
|
||||
if s.ID != 0 {
|
||||
if _, ok := forbiddenSources[s.Source]; ok {
|
||||
return fmt.Errorf("forbidden source name: '%s'", s.Source)
|
||||
}
|
||||
if !rgxSource.MatchString(s.Source) {
|
||||
return fmt.Errorf("source name does follow the naming convention: '%s'", s.Source)
|
||||
}
|
||||
}
|
||||
usedIDs[s.ID] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validates returns nil if the Registry is valid, and an error otherwise.
|
||||
// For more details regarding which constraints are checked for validation,
|
||||
// refer to: https://github.com/falcosecurity/plugins#registering-a-new-plugin
|
||||
func (r *Registry) Validate() error {
|
||||
forbiddenSources := make(map[string]bool)
|
||||
for _, s := range r.ReservedSources {
|
||||
forbiddenSources[s] = true
|
||||
}
|
||||
|
||||
ids := make(map[uint]bool)
|
||||
names := make(map[string]bool)
|
||||
for _, p := range r.Plugins {
|
||||
if !rgxName.MatchString(p.Name) {
|
||||
return fmt.Errorf("plugin name does follow the naming convention: '%s'", p.Name)
|
||||
}
|
||||
if _, ok := names[p.Name]; ok {
|
||||
return fmt.Errorf("plugin name is not unique: '%s'", p.Name)
|
||||
}
|
||||
if err := p.Capabilities.Sourcing.validate(ids, forbiddenSources); err != nil {
|
||||
return err
|
||||
}
|
||||
names[p.Name] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/falcosecurity/plugins/build/registry/pkg/registry"
|
||||
)
|
||||
|
||||
func DoTable(registryFile, subFile, subTag string) error {
|
||||
r, err := registry.LoadRegistryFromFile(registryFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
table, err := formatMarkdownTable(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(subFile) == 0 {
|
||||
fmt.Println(table)
|
||||
} else {
|
||||
if len(subTag) == 0 {
|
||||
return fmt.Errorf("subtag flag is required")
|
||||
}
|
||||
content, err := os.ReadFile(subFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pieces := strings.SplitN(string(content), subTag, 3)
|
||||
if len(pieces) != 3 {
|
||||
return fmt.Errorf("can't find two instances of subtag in text file: '%s'", subTag)
|
||||
}
|
||||
contentStr := fmt.Sprintf("%s%s\n%s\n%s%s", pieces[0], subTag, table, subTag, pieces[2])
|
||||
if err = os.WriteFile(subFile, []byte(contentStr), 0666); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatMarkdownTable(r *registry.Registry) (string, error) {
|
||||
var ret strings.Builder
|
||||
ret.WriteString("| Name | Capabilities | Description\n")
|
||||
ret.WriteString("| --- | --- | --- |\n")
|
||||
for _, p := range r.Plugins {
|
||||
line := fmt.Sprintf("| %s | %s | %s <br/><br/> Authors: %s <br/> License: %s |\n",
|
||||
formatMarkdownStringWithURL(r, p.Name, p.URL),
|
||||
formatMarkdownCapabilities(r, &p.Capabilities),
|
||||
formatMarkdownStringNotAvailable(r, p.Description),
|
||||
formatMarkdownStringWithURL(r, p.Authors, p.Contact),
|
||||
formatMarkdownStringNotAvailable(r, p.License),
|
||||
)
|
||||
ret.WriteString(line)
|
||||
}
|
||||
return ret.String(), nil
|
||||
}
|
||||
|
||||
func formatMarkdownCapabilities(r *registry.Registry, caps *registry.Capabilities) string {
|
||||
var ret strings.Builder
|
||||
if caps.Sourcing.Supported {
|
||||
ret.WriteString(fmt.Sprintf("**Event Sourcing** <br/>ID: %d <br/>`%s`",
|
||||
caps.Sourcing.ID,
|
||||
caps.Sourcing.Source,
|
||||
))
|
||||
}
|
||||
if caps.Extraction.Supported {
|
||||
if ret.Len() > 0 {
|
||||
ret.WriteString(" <br/>")
|
||||
}
|
||||
ret.WriteString("**Field Extraction** <br/> ")
|
||||
if len(caps.Extraction.Sources) == 0 {
|
||||
if caps.Sourcing.Supported {
|
||||
ret.WriteString("`" + caps.Sourcing.Source + "`")
|
||||
} else {
|
||||
ret.WriteString("*All Sources*")
|
||||
}
|
||||
} else {
|
||||
var sources []string
|
||||
for _, s := range caps.Extraction.Sources {
|
||||
sources = append(sources, "`"+s+"`")
|
||||
}
|
||||
ret.WriteString(strings.Join(sources, ", "))
|
||||
}
|
||||
}
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func formatMarkdownStringNotAvailable(r *registry.Registry, s string) string {
|
||||
if len(s) == 0 {
|
||||
return "N/A"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func formatMarkdownStringWithURL(r *registry.Registry, s, url string) string {
|
||||
if len(url) == 0 {
|
||||
return formatMarkdownStringNotAvailable(r, s)
|
||||
}
|
||||
return fmt.Sprintf("[%s](%s)", formatMarkdownStringNotAvailable(r, s), url)
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Copyright (C) 2022 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTableSubTag = "<!-- REGISTRY -->"
|
||||
)
|
||||
|
||||
func loadRegistryFromFile(fname string) (*Registry, error) {
|
||||
file, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
return LoadRegistry(file)
|
||||
}
|
||||
|
||||
func doCheck(fileName string) error {
|
||||
registry, err := loadRegistryFromFile(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return registry.Check()
|
||||
}
|
||||
|
||||
func doTable(registryFile, subFile, subTag, contentType string) error {
|
||||
registry, err := loadRegistryFromFile(registryFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = registry.Check()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
table, err := registry.FormatMarkdownTable(contentType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(subFile) == 0 {
|
||||
fmt.Println(table)
|
||||
} else {
|
||||
if len(subTag) == 0 {
|
||||
return fmt.Errorf("subtag flag is required")
|
||||
}
|
||||
content, err := ioutil.ReadFile(subFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pieces := strings.SplitN(string(content), subTag, 3)
|
||||
if len(pieces) != 3 {
|
||||
return fmt.Errorf("can't find two instances of subtag in text file: '%s'", subTag)
|
||||
}
|
||||
contentStr := fmt.Sprintf("%s%s\n%s\n%s%s", pieces[0], subTag, table, subTag, pieces[2])
|
||||
if err = ioutil.WriteFile(subFile, []byte(contentStr), 0666); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
checkCmd := &cobra.Command{
|
||||
Use: "check <filename>",
|
||||
Short: "Verify the correctness of a plugin registry YAML file",
|
||||
Args: cobra.ExactArgs(1),
|
||||
DisableFlagsInUseLine: true,
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
return doCheck(args[0])
|
||||
},
|
||||
}
|
||||
|
||||
var tableSubFileName string
|
||||
var tableSubTab string
|
||||
var tableType string
|
||||
tableCmd := &cobra.Command{
|
||||
Use: "table <filename>",
|
||||
Short: "Format a plugin registry YAML file in a MarkDown table",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
return doTable(args[0], tableSubFileName, tableSubTab, tableType)
|
||||
},
|
||||
}
|
||||
tableFlags := tableCmd.Flags()
|
||||
tableFlags.StringVar(&tableSubTab, "subtag", defaultTableSubTag, "A tag that delimits the start and the end of the text section to substitute with the generated table.")
|
||||
tableFlags.StringVar(&tableSubFileName, "subfile", "", "If specified, the table will be written inside the file at this path, inserting it between the first two instances of the substitution tag.")
|
||||
tableFlags.StringVar(&tableType, "type", sourcePluginsTableContentType, "The type of content to be included in the table")
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "registry",
|
||||
Version: "0.1.0",
|
||||
}
|
||||
rootCmd.AddCommand(checkCmd)
|
||||
rootCmd.AddCommand(tableCmd)
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Printf("error: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
Copyright (C) 2022 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
sourcePluginsTableContentType = "plugins-source"
|
||||
extractorPluginsTableContentType = "plugins-extractor"
|
||||
)
|
||||
|
||||
func (r *Registry) FormatMarkdownTable(contentType string) (string, error) {
|
||||
var ret strings.Builder
|
||||
wrapNotAvailable := func(s string) string {
|
||||
if len(s) == 0 {
|
||||
return "N/A"
|
||||
}
|
||||
return s
|
||||
}
|
||||
formatWithURL := func(s string, url string) string {
|
||||
if len(url) == 0 {
|
||||
return wrapNotAvailable(s)
|
||||
}
|
||||
return fmt.Sprintf("[%s](%s)", wrapNotAvailable(s), url)
|
||||
}
|
||||
|
||||
switch contentType {
|
||||
case sourcePluginsTableContentType:
|
||||
ret.WriteString("| ID | Name | Event Source | Description | Info |\n")
|
||||
ret.WriteString("| --- | --- | --- | --- | --- |\n")
|
||||
for _, s := range r.Plugins.Source {
|
||||
line := fmt.Sprintf("| %d | %s | `%s` | %s | Authors: %s <br/> License: %s |\n",
|
||||
s.ID,
|
||||
formatWithURL(s.Name, s.URL),
|
||||
wrapNotAvailable(s.Source),
|
||||
wrapNotAvailable(s.Description),
|
||||
formatWithURL(s.Authors, s.Contact),
|
||||
wrapNotAvailable(s.License),
|
||||
)
|
||||
ret.WriteString(line)
|
||||
}
|
||||
case extractorPluginsTableContentType:
|
||||
ret.WriteString("| Name | Extract Event Sources | Description | Info |\n")
|
||||
ret.WriteString("| --- | --- | --- | --- |\n")
|
||||
for _, e := range r.Plugins.Extractor {
|
||||
sources := make([]string, 0)
|
||||
for _, s := range e.Sources {
|
||||
sources = append(sources, fmt.Sprintf("`%s`", s))
|
||||
}
|
||||
line := fmt.Sprintf("| %s | %s | %s | Authors: %s <br/> License: %s |\n",
|
||||
formatWithURL(e.Name, e.URL),
|
||||
wrapNotAvailable(strings.Join(sources, ", ")),
|
||||
wrapNotAvailable(e.Description),
|
||||
formatWithURL(e.Authors, e.Contact),
|
||||
wrapNotAvailable(e.License),
|
||||
)
|
||||
ret.WriteString(line)
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("unknown table content type: %s", contentType)
|
||||
}
|
||||
|
||||
return ret.String(), nil
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright (C) 2022 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/go-yaml/yaml"
|
||||
)
|
||||
|
||||
type Source struct {
|
||||
ID uint `yaml:"id"`
|
||||
Source string `yaml:"source"`
|
||||
Name string `yaml:"name"`
|
||||
Description string `yaml:"description"`
|
||||
Authors string `yaml:"authors"`
|
||||
Contact string `yaml:"contact"`
|
||||
URL string `yaml:"url"`
|
||||
License string `yaml:"license"`
|
||||
Reserved bool `yaml:"reserved"`
|
||||
}
|
||||
|
||||
type Extractor struct {
|
||||
Sources []string `yaml:"sources"`
|
||||
Name string `yaml:"name"`
|
||||
Description string `yaml:"description"`
|
||||
Authors string `yaml:"authors"`
|
||||
Contact string `yaml:"contact"`
|
||||
URL string `yaml:"url"`
|
||||
License string `yaml:"license"`
|
||||
Reserved bool `yaml:"reserved"`
|
||||
}
|
||||
|
||||
type Plugins struct {
|
||||
Source []Source `yaml:"source"`
|
||||
Extractor []Extractor `yaml:"extractor"`
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
Plugins Plugins `yaml:"plugins"`
|
||||
ReservedSources []string `yaml:"reserved_sources"`
|
||||
}
|
||||
|
||||
func LoadRegistry(r io.Reader) (*Registry, error) {
|
||||
decoder := yaml.NewDecoder(r)
|
||||
registry := &Registry{}
|
||||
if err := decoder.Decode(registry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return registry, nil
|
||||
}
|
|
@ -1,2 +1 @@
|
|||
version
|
||||
utils
|
||||
version
|
|
@ -1,6 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2023 The Falco Authors.
|
||||
# Copyright (C) 2022 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/falcosecurity/plugins/build/utils
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/spf13/pflag v1.0.6
|
||||
require github.com/spf13/pflag v1.0.5
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
//go:build (linux && cgo) || (darwin && cgo) || (freebsd && cgo)
|
||||
// +build linux,cgo darwin,cgo freebsd,cgo
|
||||
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
Copyright (C) 2022 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -43,7 +42,7 @@ import (
|
|||
#include <stdio.h>
|
||||
|
||||
static uintptr_t pluginOpen(const char* path, char** err) {
|
||||
void* h = dlopen(path, RTLD_NOW|RTLD_GLOBAL|RTLD_DEEPBIND);
|
||||
void* h = dlopen(path, RTLD_NOW|RTLD_GLOBAL);
|
||||
if (h == NULL) {
|
||||
*err = (char*)dlerror();
|
||||
}
|
||||
|
@ -75,9 +74,26 @@ static char* get_version(uintptr_t h, char** err) {
|
|||
*/
|
||||
import "C"
|
||||
|
||||
var rgxVersion = regexp.MustCompile(`^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?$`)
|
||||
var rgxHash = regexp.MustCompile(`^[0-9a-z]+$`)
|
||||
var rgxName = regexp.MustCompile(`^[a-z]+[a-z0-9_\-]*$`)
|
||||
var rgxVersion *regexp.Regexp
|
||||
var rgxHash *regexp.Regexp
|
||||
var rgxName *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
// see: https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
||||
rgxVersion, err = regexp.Compile(`^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?$`)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
rgxHash, err = regexp.Compile(`^[0-9a-z]+$`)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
rgxName, err = regexp.Compile(`^[a-z]+[a-z0-9_]*$`)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func pluginInfo(path string) (name, version string, err error) {
|
||||
path, err = filepath.Abs(path)
|
||||
|
@ -99,19 +115,14 @@ func pluginInfo(path string) (name, version string, err error) {
|
|||
err = errors.New("cannot get name of " + path + ": " + C.GoString(cErr))
|
||||
return
|
||||
}
|
||||
// we need to convert immediately the pointer into a string
|
||||
// otherwise the pointer could change see plugin sdk cpp
|
||||
name = C.GoString(cName)
|
||||
|
||||
cVer := C.get_version(h, &cErr)
|
||||
if cVer == nil {
|
||||
err = errors.New("cannot get version of " + path + ": " + C.GoString(cErr))
|
||||
return
|
||||
}
|
||||
// Same as before
|
||||
version = C.GoString(cVer)
|
||||
|
||||
return
|
||||
return C.GoString(cName), C.GoString(cVer), nil
|
||||
}
|
||||
|
||||
func git(args ...string) (output []string, err error) {
|
||||
|
@ -163,18 +174,13 @@ func main() {
|
|||
var hash string
|
||||
|
||||
// get last tag
|
||||
// It matches the old tag in "pluginName-version" or the new one "plugins/pluginName/semver"
|
||||
tags, err := git("describe", "--tags", "--abbrev=0", "--match", name+`-[0-9]*`, "--match", "plugins/"+name+"/v*")
|
||||
tags, err := git("describe", "--tags", "--abbrev=0", "--match", name+`-*`)
|
||||
if err == nil {
|
||||
if len(tags) == 0 {
|
||||
fail(errors.New("no git tag found for: " + name))
|
||||
}
|
||||
lastTag := tags[0]
|
||||
if strings.HasPrefix(lastTag, name) {
|
||||
lastVer = strings.Replace(lastTag, name+"-", "", 1)
|
||||
} else {
|
||||
lastVer = strings.Replace(lastTag, "plugins/"+name+"/v", "", 1)
|
||||
}
|
||||
lastVer = strings.Replace(lastTag, name+"-", "", 1)
|
||||
if !rgxVersion.MatchString(lastVer) {
|
||||
fail(errors.New("plugin latest released version not compatible with SemVer: " + lastTag))
|
||||
}
|
||||
|
@ -205,14 +211,11 @@ func main() {
|
|||
|
||||
} else {
|
||||
// stable versions MUST have a precise tag matching plugin name and version
|
||||
expectedTag := "plugins/" + name + "/v" + version
|
||||
expectedTag := name + "-" + version
|
||||
tags, err := git("--no-pager", "tag", "--points-at", "HEAD")
|
||||
if err != nil {
|
||||
fail(err)
|
||||
}
|
||||
if len(tags) == 0 || len(tags[0]) == 0 {
|
||||
fail(errors.New("there are no tags pointing at HEAD"))
|
||||
}
|
||||
for _, tag := range tags {
|
||||
if tag == expectedTag {
|
||||
fmt.Println(version)
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2025 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
plugin=$1
|
||||
|
||||
if [ -z "$plugin" ]; then
|
||||
echo "Usage changelog-gen.sh <plugin_name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tool=./build/changelog/bin/changelog
|
||||
|
||||
to=""
|
||||
from=""
|
||||
tags="$(git tag -l | grep -E -e ${plugin}-[0-9]+.[0-9]+.[0-9]+ -e ${plugin}/v[0-9]+.[0-9]+.[0-9]+ | grep -E -v ${plugin}-[0-9]+.[0-9]+.[0-9]+-rc | sort -V -r)"
|
||||
|
||||
# print title
|
||||
echo "# Changelog"
|
||||
echo ""
|
||||
|
||||
# generate entry for upcoming tag, if any
|
||||
head="$(git rev-parse HEAD)"
|
||||
dev_changelog="$(${tool} --from="" --to=${head} --plugin=${plugin})"
|
||||
if [ ! -z "$dev_changelog" ]; then
|
||||
echo "## dev build (unreleased)"
|
||||
echo ""
|
||||
echo "$dev_changelog"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# generate entry for each tag
|
||||
for tag in $tags
|
||||
do
|
||||
from=$tag
|
||||
if [ ! -z "$to" ]; then
|
||||
ver=""
|
||||
# support both the old and new tag formats
|
||||
if [[ $to == plugins/* ]]; then
|
||||
ver="$(echo ${to} | sed -e s/^plugins\\/${plugin}\\///)"
|
||||
else
|
||||
ver="$(echo ${to} | sed -e s/^${plugin}-// -e s/^/v/)"
|
||||
fi
|
||||
echo "## ${ver}"
|
||||
echo ""
|
||||
${tool} --from=${from} --to=${to} --plugin=${plugin}
|
||||
echo ""
|
||||
fi
|
||||
to=$tag
|
||||
done
|
||||
|
||||
# generate last entry for first tag, starting from the first commit
|
||||
if [ -n "$to" ]; then
|
||||
from="$(git rev-list --max-parents=0 HEAD)"
|
||||
# support both the old and new tag formats
|
||||
if [[ $to == plugins/* ]]; then
|
||||
ver="$(echo ${to} | sed -e s/^plugins\\/${plugin}\\///)"
|
||||
else
|
||||
ver="$(echo ${to} | sed -e s/^${plugin}-// -e s/^/v/)"
|
||||
fi
|
||||
echo "## ${ver}"
|
||||
echo ""
|
||||
${tool} --from=${from} --to=${to} --plugin=${plugin}
|
||||
echo ""
|
||||
fi
|
|
@ -2,69 +2,14 @@
|
|||
|
||||
This page summarizes some best practices and guidelines that can be useful to developers that are getting started with the [plugin system of Falco](https://falco.org/docs/plugins/). The [Developers Guide](https://falco.org/docs/plugins/developers-guide/) is mostly focused on the technical aspects of plugin development. In contrast, here we provide some guidance on more high-level points that may occur during the design and implementation phases.
|
||||
|
||||
## Plugin Directory Structure
|
||||
|
||||
Currently, Go is the most used language for writing plugins. So, below you can find the recommended layout for Go plugin projects. For other languages, you can adapt the layout accordingly.
|
||||
|
||||
### `/pkg`
|
||||
|
||||
Reusable Go packages that other plugins or projects can use. This directory is not mandatory but is highly recommended.
|
||||
|
||||
### `/plugin`
|
||||
|
||||
This directory contains the plugin entry point. This directory should have only one `.go` file, named as your plugin. This file must define the `main` package (and an empty `main()` function) per CGO requirement.
|
||||
Usually, this file also imports packages from `/pkg` and defines an `init()` function to register the plugin capabilities (that's required if you are using the [plugin-go-sdk](https://github.com/falcosecurity/plugin-sdk-go)).
|
||||
|
||||
### `/rules`
|
||||
|
||||
This directory is optional. If you want to distribute rules files for your plugin, you can put them in this directory.
|
||||
The building system of this repository will automatically build and publish them as a `.tar.gz` archive under [https://download.falco.org/?prefix=plugins/](https://download.falco.org/?prefix=plugins/).
|
||||
|
||||
### `/Makefile`
|
||||
|
||||
Providing a `Makefile` is mandatory for plugins hosted by this repository. The building system of this repository will use:
|
||||
- `make` to build the plugin binary
|
||||
- `make clean` to clean the built artifacts
|
||||
- `make rules` to build the rules files (this is optional)
|
||||
|
||||
Below you can find an example of a typical `Makefile` for a plugin hosted by this repository.
|
||||
|
||||
```Makefile
|
||||
SHELL=/bin/bash -o pipefail
|
||||
GO ?= go
|
||||
|
||||
NAME := <YOUR-PLUGIN-NAME-HERE>
|
||||
OUTPUT := lib$(NAME).so
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
GODEBUGFLAGS= GODEBUG=cgocheck=1
|
||||
else
|
||||
GODEBUGFLAGS= GODEBUG=cgocheck=0
|
||||
endif
|
||||
|
||||
all: $(OUTPUT)
|
||||
|
||||
clean:
|
||||
@rm -f *.so *.h
|
||||
|
||||
$(OUTPUT):
|
||||
@$(GODEBUGFLAGS) $(GO) build -buildmode=c-shared -o $(OUTPUT) ./plugin
|
||||
```
|
||||
|
||||
## Configuration in Source Plugins
|
||||
|
||||
One peculiarity of plugins with event source capability is how they can accept user configurations. Other plugins can only be configured during the initialization phase through `plugin_init()`, whereas source plugins also take some parameters while opening the event stream with `plugin_open()`. This creates some ambiguity on **which** information should go inside the init configuration and what should be part of the open parameters instead.
|
||||
One of the main differences between source and extractor plugins is the way they can accept user configurations. Extractor plugins can only be configured during the initialization phase through `plugin_init()`, whereas source plugins also accept and some parameters while opening the event stream with `plugin_open()`. This creates some ambiguity on **which** information should go inside the init configuration, and what should be part of the open parameters instead.
|
||||
|
||||
There's no silver bullet for this problem, and the solution strictly depends on the use cases of your plugin. However, there are some principles you can follow.
|
||||
|
||||
- The [init configuration](https://falco.org/docs/configuration/#plugins) should contain information that is used during the whole plugin lifecycle and that is used across both field extraction and event generation
|
||||
- The init configuration is the right place for structured data. In fact, in most cases, plugins accept JSON strings as a configuration and also expose a schema describing/documenting the expected data format (see [`plugin_get_init_schema`](https://falco.org/docs/plugins/plugin-api-reference/#get-init-schema) for more details)
|
||||
- Init configuration parameters should have the following annotations. See the [JSON Schema Validation specification](https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta) for more details:
|
||||
- `title`, which provides a short user-facing name for the parameter.
|
||||
- `description`, which describes the parameter using a sentence or a short paragraph.
|
||||
- `default` (optional), which provides the default value of the parameter.
|
||||
- `required` (optional), which notes that the parameter value is required.
|
||||
- `examples` (optional), which provides example values for the parameter.
|
||||
- The init configuration is the right place for structured data. In fact, in most cases, plugins accept JSON strings as a configuration and also expose a schema describing/documenting the expected data format (see [`plugin_get_init_schema`](https://falco.org/docs/plugins/plugin-api-reference/#const-char-plugin-get-init-schema-ss-plugin-schema-type-schema-type-required-no) for more details)
|
||||
- The open parameters should contain information that is only relevant for opening a specific event source, and their lifecycle ends at the invocation of `plugin_close()`
|
||||
- The open parameters should contain minimal and non-structured information, such as a URI or a resource descriptor string. This is the reason why the framework does not support any schema definition for open parameters and treats them as an opaque string. Ideally, if more than one parameter is required to open a data source, comma-separated string concatenation is preferable to structured data formats such as JSON
|
||||
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
# Plugin IDs (Sourcing Capability Only)
|
||||
|
||||
Using a unique `id` is mandatory to maintain interoperability across all plugins with _event sourcing_ capability. When a plugin is loaded by a compatible application (e.g., Falco), the `id` is used to route events to the correct plugin. Indeed, attempting to load two or more plugins using the same `id` will result in an error.
|
||||
|
||||
For this reason, The Falco Project maintains a [public registry of plugins](https://github.com/falcosecurity/plugins/blob/main/README.md#registering-a-new-plugin), which allows the assignment of a unique `id` for your plugin. However, some plugins may not be registered in the public registry. For example, if you are privately developing a plugin for your own use, you might use any `id` you want. To avoid conflicts in these situations, this document mandates general rules regarding `id` assignment and reservation.
|
||||
|
||||
## ID Blocks
|
||||
|
||||
The following ID ranges are designated for specific purposes:
|
||||
|
||||
| Block name | ID range | # of IDs | Description |
|
||||
|---|---|---|---|
|
||||
| Public | 0–1073741823 (30-bit) | 1073741824 | Used in the public registry. Single IDs in this range can be [assigned](#assigning-an-id) or [reserved](#reserving-an-id). |
|
||||
| Private | 1073741824–2147483647 (30-bit) | 1073741824 | Used for private plugins (think of this range as the equivalent of 192.168.0.0/16 in networks). Organizations may use this range for plugins intended for their private domain. Interoperability is not guaranteed. |
|
||||
| Reserved | 2147483648-3221225471 (30-bit) | 1073741824 | This range is reserved for future use and must not be used under any circumstances. |
|
||||
| Internal | 3221225472-4294967295 (30-bit) | 1073741824 | This range is reserved for internal use and must not be used by plugins. It might be used by the plugin framework implementation for technical purposes. |
|
||||
|
||||
Notes:
|
||||
- An `id` is a 32-bit unsigned integer. The MSBs are used to identify the block of IDs.
|
||||
- Only IDs up to 1073741823 can be requested for use in the public registry.
|
||||
- Only IDs up to 2147483647 can be used by plugins.
|
||||
|
||||
## Assigning an ID
|
||||
|
||||
The public registry is intended for assigning IDs to plugins that are publicly available. If you want to share your plugin with the community, you should follow the instructions reported in the [Registering a new plugin](../README.md#registering-a-new-plugin) section of this repository's documentation.
|
||||
|
||||
When making your request, please choose the next available ID in the [registry.yaml](../registry.yaml) file. The `id` will be definitively assigned to your plugin once the corresponding PR is merged, and the [registry.yaml](../registry.yaml) file is updated.
|
||||
|
||||
## Reserving an ID
|
||||
|
||||
For particular technical purposes or special cases, an `id` can be reserved so that it will not be assigned to any specific plugin. Notably, id 999 has been reserved for source plugin development. Any plugin author can temporarily use this `id`; however, it can't be assigned to any specific plugin and must not be used for purposes other than local development.
|
||||
|
||||
To reserve an `id`, you can use the same procedure for [registering a new plugin](../README.md#registering-a-new-plugin) and specify the `reserved: true` option.
|
||||
|
||||
Requests for `id` reservation will be evaluated on a case-by-case basis. The Falco Project reserves the right to reject any request for any reason.
|
|
@ -1,40 +0,0 @@
|
|||
### Registering a Plugin
|
||||
|
||||
Registering your plugin inside the registry helps ensure that some technical constraints are respected, such as that a [given ID is used by exactly one plugin with event source capability](https://falco.org/docs/concepts/plugins/architecture/#plugin-event-ids) and allows plugin authors to [coordinate about event source formats](https://falco.org/docs/concepts/plugins/architecture/#plugin-event-sources-and-interoperability). Moreover, this is a great way to share your plugin project with the community and engage with it, thus gaining new users and **increasing its visibility**. We encourage you to register your plugin in this registry before publishing it. You can add your plugins in this registry regardless of where its source code is hosted (there's a `url` field for this specifically).
|
||||
|
||||
The registration process involves adding an entry about your plugin inside the [registry.yaml](../registry.yaml) file by creating a Pull Request in this repository. Please be mindful of a few constraints that are automatically checked and required for your plugin to be accepted:
|
||||
|
||||
- The `name` field is mandatory and must be **unique** across all the plugins in the registry
|
||||
- *(Sourcing Capability Only)* The `id` field is mandatory and must be **unique** in the registry across all the plugins with event source capability
|
||||
- See [docs/plugin-ids.md](plugin-ids.md) for more information about plugin IDs
|
||||
- The plugin `name` must match this [regular expression](https://en.wikipedia.org/wiki/Regular_expression): `^[a-z]+[a-z0-9-_\-]*$` (however, its not recommended to use `_` in the name, unless you are trying to match the name of a source or for particular reasons)
|
||||
- The `source` *(Sourcing Capability Only)* and `sources` *(Extraction Capability Only)* must match this [regular expression](https://en.wikipedia.org/wiki/Regular_expression): `^[a-z]+[a-z0-9_]*$`
|
||||
- The `url` field should point to the plugin source code
|
||||
- The `rules_url` field should point to the default ruleset, if any
|
||||
|
||||
For reference, here's an example of an entry for a plugin with both event sourcing and field extraction capabilities:
|
||||
```yaml
|
||||
- name: k8saudit
|
||||
description: ...
|
||||
authors: ...
|
||||
contact: ...
|
||||
maintainers:
|
||||
- name: The Falco Authors
|
||||
email: cncf-falco-dev@lists.cncf.io
|
||||
keywords:
|
||||
- audit
|
||||
- audit-log
|
||||
- audit-events
|
||||
- kubernetes
|
||||
url: https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit
|
||||
rules_url: https://github.com/falcosecurity/plugins/tree/main/plugins/k8saudit/rules
|
||||
url: ...
|
||||
license: ...
|
||||
capabilities:
|
||||
sourcing:
|
||||
supported: true
|
||||
id: 2
|
||||
source: k8s_audit
|
||||
extraction:
|
||||
supported: true
|
||||
```
|
|
@ -1,6 +0,0 @@
|
|||
*.so
|
||||
*.a
|
||||
*.o
|
||||
.vscode
|
||||
build*
|
||||
libanomalydetection.so
|
|
@ -1,38 +0,0 @@
|
|||
# Changelog
|
||||
|
||||
## dev build (unreleased)
|
||||
|
||||
* [`406c517`](https://github.com/falcosecurity/plugins/commit/406c517) update(anomalydetection): tweak inits when count_min_sketch disabled + better...
|
||||
|
||||
* [`cb0fdb1`](https://github.com/falcosecurity/plugins/commit/cb0fdb1) update(anomalydetection): update documentation
|
||||
|
||||
* [`79c085e`](https://github.com/falcosecurity/plugins/commit/79c085e) update(anomalydetection): helper new filtercheck / output field anomaly.falco...
|
||||
|
||||
* [`489ef6d`](https://github.com/falcosecurity/plugins/commit/489ef6d) update(anomalydetection): ability to reset data structures w/ timers
|
||||
|
||||
* [`d4e72b8`](https://github.com/falcosecurity/plugins/commit/d4e72b8) update(anomalydetection): more usage safeguards and info log messages
|
||||
|
||||
* [`23bf05e`](https://github.com/falcosecurity/plugins/commit/23bf05e) update(anomalydetection): add some fallbacks / evt param extraction in cases ...
|
||||
|
||||
* [`1e8052c`](https://github.com/falcosecurity/plugins/commit/1e8052c) update(anomalydetection): add some custom behavior profile short-cut fields o...
|
||||
|
||||
* [`6a448c2`](https://github.com/falcosecurity/plugins/commit/6a448c2) update(anomalydetection): add MutexGuard (adopted from libs) to sketches data...
|
||||
|
||||
* [`f720e4a`](https://github.com/falcosecurity/plugins/commit/f720e4a) update(anomalydetection): finish currently supported behavior profile filterc...
|
||||
|
||||
* [`14a58d3`](https://github.com/falcosecurity/plugins/commit/14a58d3) update(anomalydetection): add lastevent_fd + enhance robustness / tests + sta...
|
||||
|
||||
* [`27747eb`](https://github.com/falcosecurity/plugins/commit/27747eb) update(anomalydetection): unit tests for proc lineage + add filterchecks 1/n
|
||||
|
||||
* [`fa2c05e`](https://github.com/falcosecurity/plugins/commit/fa2c05e) update(anomalydetection): populate info for proc args
|
||||
|
||||
* [`faf6636`](https://github.com/falcosecurity/plugins/commit/faf6636) update(anomalydetection): sync plugin to latest SDK changes
|
||||
|
||||
* [`6a834a3`](https://github.com/falcosecurity/plugins/commit/6a834a3) new(anomalydetection): init config + start behavior profile extraction
|
||||
|
||||
* [`73c11bd`](https://github.com/falcosecurity/plugins/commit/73c11bd) new(anomalydetection): start unit tests + bump libs and sdk
|
||||
|
||||
* [`f778922`](https://github.com/falcosecurity/plugins/commit/f778922) cleanup(anomalydetection): cms class updates
|
||||
|
||||
* [`6b89390`](https://github.com/falcosecurity/plugins/commit/6b89390) new(anomalydetection): init plugin / start dev
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2024 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
option(BUILD_TESTS "Enable tests" ON)
|
||||
|
||||
# Project metadata
|
||||
project(
|
||||
anomalydetection
|
||||
VERSION 0.1.0
|
||||
DESCRIPTION "Falco Anomaly Detection Plugin"
|
||||
LANGUAGES CXX)
|
||||
|
||||
# Dependencies
|
||||
include(FetchContent)
|
||||
include(plugin-sdk-cpp)
|
||||
include(libs) # Temporarily include libs for initial dev
|
||||
include(xxhash)
|
||||
|
||||
# Project target
|
||||
file(GLOB_RECURSE anomalydetection_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
|
||||
add_library(anomalydetection SHARED ${anomalydetection_SOURCES} )
|
||||
set_target_properties(anomalydetection PROPERTIES CXX_EXTENSIONS OFF)
|
||||
|
||||
# Project compilation options
|
||||
target_compile_options(anomalydetection PRIVATE "-fPIC")
|
||||
target_compile_options(anomalydetection PRIVATE "-Wl,-z,relro,-z,now")
|
||||
target_compile_options(anomalydetection PRIVATE "-fstack-protector-strong")
|
||||
# When compiling in Debug mode, this will define the DEBUG symbol for use in your code
|
||||
target_compile_options(anomalydetection PUBLIC "$<$<CONFIG:DEBUG>:-DDEBUG>")
|
||||
target_compile_features(anomalydetection PUBLIC cxx_std_17)
|
||||
|
||||
# Project includes
|
||||
target_include_directories(
|
||||
anomalydetection PRIVATE "${PLUGIN_SDK_INCLUDE}" "${XXHASH_INCLUDE}" "${LIBS_INCLUDE}")
|
||||
|
||||
# Project linked libraries
|
||||
target_link_libraries(anomalydetection ${_REFLECTION})
|
||||
|
||||
# Testing
|
||||
if(BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
|
@ -1,36 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2024 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
NAME := anomalydetection
|
||||
OUTPUT := lib$(NAME).so
|
||||
|
||||
all: $(OUTPUT)
|
||||
|
||||
clean:
|
||||
rm -rf build $(OUTPUT)
|
||||
# Temporarily include libs for initial dev
|
||||
$(OUTPUT):
|
||||
mkdir -p build \
|
||||
&& cd build \
|
||||
&& cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DMINIMAL_BUILD=ON \
|
||||
-DUSE_BUNDLED_LIBELF=OFF \
|
||||
-DCREATE_TEST_TARGETS=OFF \
|
||||
../ \
|
||||
&& make -j6 anomalydetection \
|
||||
&& cp ./$(OUTPUT) ../$(OUTPUT)
|
||||
|
||||
readme:
|
||||
@$(READMETOOL) -p ./$(OUTPUT) -f README.md
|
|
@ -1,319 +0,0 @@
|
|||
# Falcosecurity `anomalydetection` Plugin
|
||||
|
||||
**This plugin is experimental and under development**
|
||||
|
||||
This `anomalydetection` plugin has been created upon this [Proposal](https://github.com/falcosecurity/falco/blob/master/proposals/20230620-anomaly-detection-framework.md).
|
||||
|
||||
## Introduction
|
||||
|
||||
The `anomalydetection` plugin enhances {syscall} event analysis by incorporating anomaly detection estimates for probabilistic filtering.
|
||||
|
||||
### Functionality
|
||||
|
||||
The initial scope focuses exclusively on "CountMinSketch Powered Probabilistic Counting and Filtering" for a subset of syscalls and a selection of options for defining behavior profiles. This limitation is due to current restrictions related to the plugin API and SDK layout.
|
||||
|
||||
The new framework primarily aims to improve the usability of standard Falco rules. It may reduce the need for precise rule tuning, leverages probabilistic count estimates to auto-tune noisy rules on the fly, and enables the creation of broader Falco rules. Read more in the [Proposal](https://github.com/falcosecurity/falco/blob/master/proposals/20230620-anomaly-detection-framework.md).
|
||||
|
||||
### TL;DR
|
||||
|
||||
The official documentation will eventually be available on the Falco [Plugins](https://falco.org/docs/plugins/) site. Therefore, consider this README as not being a complete documentation for using this plugin.
|
||||
|
||||
*Disclaimer*: Anomaly detection can mean different things to different people. It's best to keep your expectations low for this plugin's current capabilities. For now, it is focused solely on probabilistic counting.
|
||||
|
||||
What this plugin is:
|
||||
- **Initial step for real-time anomaly detection in Falco**: Introduces basic real-time anomaly detection methods on the host.
|
||||
- **Probabilistic counting**: Currently supports only probabilistic counting, with the guarantee that any overcounting remains within an acceptable error margin.
|
||||
- **Use-case dependent**: Requires careful derivation of custom use cases; no default use cases are provided at this time.
|
||||
- **Limited by current API**: Subject to several restrictions due to plugin API and other limitations.
|
||||
- **Built for future extensibility**: Designed to support more algorithms in the future, limited to those that can be implemented in a single data pass to ensure real-time performance.
|
||||
- **Documentation is insufficient**: Expect to need hands-on exploration to understand usage and restrictions.
|
||||
|
||||
What this plugin is not:
|
||||
- **Not a pre-trained AI/ML model**.
|
||||
- **Not ready out-of-the-box**: No default configuration or use cases are provided at this time.
|
||||
- **Not a universal solution**: Does not offer a one-size-fits-all approach to anomaly detection.
|
||||
- **No multi-pass algorithms**: Algorithms requiring multiple data passes are not planned; the plugin is intended to remain real-time and efficient for applicable use cases.
|
||||
- **Not yet battle-tested in production**.
|
||||
|
||||
### Outlook
|
||||
|
||||
In the near term, the plan is to expand the syscalls for which behavior profiles can be applied and to enhance the fields available for defining these profiles. The first version is quite restrictive in this regard due to current plugin API limitations. Additionally, from an algorithmic and capabilities point of view, we will explore the following:
|
||||
|
||||
- Support for HyperLogLog probabilistic distinct counting (ETA unknown).
|
||||
- Overcoming the cold start problem by loading sketch data structures and counts from previous agent runs or from test environments (ETA unknown).
|
||||
- Efficient and feasible options for real-time, single-pass time series analysis (ETA unknown).
|
||||
|
||||
### Plugin Official Name
|
||||
|
||||
`anomalydetection`
|
||||
|
||||
## Capabilities
|
||||
|
||||
The `anomalydetection` plugin implements 2 capabilities:
|
||||
|
||||
* `extraction`
|
||||
* `parsing`
|
||||
|
||||
## Supported Fields
|
||||
|
||||
Here is the current set of output / filter fields introduced by this plugin:
|
||||
|
||||
<!-- README-PLUGIN-FIELDS -->
|
||||
| NAME | TYPE | ARG | DESCRIPTION |
|
||||
|------------------------------------|----------|-------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `anomaly.count_min_sketch` | `uint64` | Index | Count Min Sketch Estimate according to the specified behavior profile for a predefined set of {syscalls} events. Access different behavior profiles/sketches using indices. For instance, anomaly.count_min_sketch[0] retrieves the first behavior profile defined in the plugins' `init_config`. |
|
||||
| `anomaly.count_min_sketch.profile` | `string` | Index | Concatenated string according to the specified behavior profile (not preserving original order). Access different behavior profiles using indices. For instance, anomaly.count_min_sketch.profile[0] retrieves the first behavior profile defined in the plugins' `init_config`. |
|
||||
| `anomaly.falco.duration_ns` | `uint64` | None | Falco agent run duration in nanoseconds, which could be useful for ignoring some rare events at launch time while Falco is just starting to build up the counts in the sketch data structures (if applicable). |
|
||||
<!-- /README-PLUGIN-FIELDS -->
|
||||
|
||||
## Usage
|
||||
|
||||
**Configuration**
|
||||
|
||||
Here's an example of configuration of `falco.yaml`:
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
- name: anomalydetection
|
||||
library_path: libanomalydetection.so
|
||||
init_config:
|
||||
count_min_sketch:
|
||||
enabled: true
|
||||
n_sketches: 3
|
||||
# `gamma_eps`: auto-calculate rows and cols; usage: [[gamma, eps], ...];
|
||||
# gamma -> error probability -> determine d / rows / number of hash functions
|
||||
# eps -> relative error -> determine w / cols / number of buckets
|
||||
gamma_eps: [
|
||||
[0.001, 0.0001],
|
||||
[0.001, 0.0001],
|
||||
[0.001, 0.0001]
|
||||
]
|
||||
# `rows_cols`: pass explicit dimensions, supersedes `gamma_eps`; usage: [[7, 27183], ...]; by default disabled when not used.
|
||||
# rows_cols: []
|
||||
behavior_profiles: [
|
||||
{
|
||||
"fields": "%container.id %custom.proc.aname.lineage.join[7] %custom.proc.aexepath.lineage.join[7] %proc.tty %proc.vpgid.name %proc.sname",
|
||||
# execve, execveat exit event codes
|
||||
"event_codes": [293, 331]
|
||||
},
|
||||
{
|
||||
"fields": "%container.id %custom.proc.aname.lineage.join[7] %custom.proc.aexepath.lineage.join[7] %proc.tty %proc.vpgid.name %proc.sname %fd.name %fd.nameraw",
|
||||
# open, openat, openat2 exit event codes
|
||||
"event_codes": [3, 307, 327]
|
||||
},
|
||||
{
|
||||
"fields": "%container.id %proc.cmdline",
|
||||
# execve, execveat exit event codes
|
||||
"event_codes": [293, 331],
|
||||
# optional config `reset_timer_ms`, resets the data structure every x milliseconds, here one hour as example
|
||||
# Remove JSON key if not wanted / needed.
|
||||
"reset_timer_ms": 3600000
|
||||
}
|
||||
]
|
||||
|
||||
load_plugins: [anomalydetection]
|
||||
```
|
||||
|
||||
The first version is quite restrictive with respect to the behavior profile's `event_codes` and `fields`. In a nutshell, you can currently define them only for a handful of event codes that Falco supports and a subset of the [Supported Fields for Conditions and Outputs](https://falco.org/docs/reference/rules/supported-fields/).
|
||||
|
||||
When you disable the `count_min_sketch` algorithm as shown below, all `anomaly.count_min_sketch` fields will be null.
|
||||
|
||||
```
|
||||
count_min_sketch:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
__NOTE__: Do not toggle the `enabled` key while hot reloading the config, as it currently does not get properly applied in such cases. Restart Falco with the `count_min_sketch` either enabled or disabled; subsequent reloads will work as expected.
|
||||
|
||||
**Behavior profiles for "execve/execveat/clone/clone3" events**
|
||||
|
||||
Example 1:
|
||||
```
|
||||
"event_codes": [293, 331],
|
||||
```
|
||||
|
||||
Example 2:
|
||||
```
|
||||
"event_codes": [223, 335],
|
||||
```
|
||||
|
||||
You can reference a behavior profile based on "execve/execveat/clone/clone3" events in any Falco rule that monitors any supported syscall. This works because every syscall is associated with a process.
|
||||
|
||||
**Behavior profiles for "fd-related" events**
|
||||
|
||||
Example 1:
|
||||
```
|
||||
rule: (evt.type in (open, openat, openat2) and evt.dir=<)
|
||||
...
|
||||
"event_codes": [3, 307, 327],
|
||||
```
|
||||
|
||||
Example 2:
|
||||
```
|
||||
rule: (evt.type=connect and evt.dir=<)
|
||||
...
|
||||
"event_codes": [23],
|
||||
```
|
||||
|
||||
You should avoid writing rules for arbitrary syscalls using "fd-related" behavior profiles because if a syscall doesn't involve a file descriptor (fd), referencing counts that rely on fd fields won't be meaningful.
|
||||
|
||||
Here's how it works:
|
||||
- If your behavior profile includes `%fd.*` fields, all event codes in that profile must be related to file descriptors.
|
||||
- If you use an "fd-related" behavior profile with a syscall that doesn't involve a file descriptor, the count will always be zero. While Falco won't crash, the anomaly detection estimate won't function as expected.
|
||||
|
||||
References:
|
||||
- See the [Supported PPME `event codes`](#ppme-event-codes) reference below.
|
||||
- See the [Supported Behavior Profiles `fields`](#behavior-profiles-fields) reference below.
|
||||
|
||||
**Open Parameters**:
|
||||
|
||||
This plugin does not have open params.
|
||||
|
||||
**Rules**
|
||||
|
||||
This plugin does not provide any default use cases or rules at the moment. More concrete use cases may be added at a later time.
|
||||
|
||||
Example of a dummy Falco rule using the `anomalydetection` fields for local testing:
|
||||
|
||||
```yaml
|
||||
- macro: spawned_process
|
||||
condition: (evt.type in (execve, execveat) and evt.dir=<)
|
||||
- rule: execve count_min_sketch test
|
||||
desc: "execve count_min_sketch test"
|
||||
condition: spawned_process and proc.name=cat and anomaly.count_min_sketch[0] > 10
|
||||
output: '%anomaly.count_min_sketch[0] %proc.pid %proc.ppid %proc.name %user.loginuid %user.name %user.uid %proc.cmdline %container.id %evt.type %evt.res %proc.cwd %proc.sid %proc.exepath %container.image.repository'
|
||||
priority: NOTICE
|
||||
tags: [maturity_sandbox, host, container, process, anomalydetection]
|
||||
```
|
||||
|
||||
__NOTE__: Ensure you regularly execute `cat` commands. Once you have done so frequently enough, logs will start to appear. Alternatively, perform an inverse test to observe how quickly a very noisy rule gets silenced.
|
||||
|
||||
**Adoption**
|
||||
|
||||
To adopt the plugin framework, you can start by identifying rules in the [default](https://github.com/falcosecurity/rules) Falco ruleset that could benefit from auto-tuning based on your heuristics regarding counts. For example, you might broaden the scope of a rule and add an `anomaly.count_min_sketch` filter condition as a safety upper bound.
|
||||
|
||||
For initial adoption, we recommend creating new, separate rules inspired by existing upstream rules, rather than modifying rules that are already performing well in production.
|
||||
|
||||
Another approach is to duplicate a rule -- one version with and another without the anomaly detection filtering.
|
||||
|
||||
Alternatively, you can add the count estimates as output fields to provide additional forensic evidence without using the counts for on-host filtering.
|
||||
|
||||
Lastly, keep in mind that there is a configuration to reset the counts per behavior profile every x milliseconds if this suits your use case better.
|
||||
|
||||
### Running
|
||||
|
||||
This plugin requires Falco with version >= **0.38.2**.
|
||||
|
||||
1. Have Falco >= **0.38.2** installed and set up
|
||||
2. Download the plugin's shared object (or build it yourself; see instructions below) and place it under `/usr/share/falco/plugins/libanomalydetection.so`
|
||||
3. Modify the `falco.yaml` with the provided example [configuration](#configuration) above
|
||||
4. Add a rule that uses `anomaly.count_min_sketch` as an output field and/or filter to `falco_rules.yaml`, and you're ready to go!
|
||||
|
||||
|
||||
```shell
|
||||
# Read the steps above before running Falco with this plugin
|
||||
sudo falco -c falco.yaml -r falco_rules.yaml
|
||||
```
|
||||
|
||||
## Local Development
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
git clone https://github.com/falcosecurity/plugins.git
|
||||
cd plugins/plugins/anomalydetection
|
||||
rm -f libanomalydetection.so;
|
||||
rm -f build/libanomalydetection.so;
|
||||
make;
|
||||
# Copy the shared library to the expected location for `falco.yaml`, which is `library_path: libanomalydetection.so`
|
||||
sudo mkdir -p /usr/share/falco/plugins/;
|
||||
sudo cp -f libanomalydetection.so /usr/share/falco/plugins/libanomalydetection.so;
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
|
||||
### PPME event codes
|
||||
|
||||
Read this [blog post](https://falco.org/blog/adaptive-syscalls-selection/) to learn more about Falco's internal PPME event codes compared to the syscall names you are used to using in Falco rules.
|
||||
|
||||
The list below is complete, and no other event codes from Falco can be used for the behavior profiles at the moment. The binary will error out if used incorrectly. Thank you for your patience.
|
||||
|
||||
```CPP
|
||||
typedef enum {
|
||||
PPME_SYSCALL_OPEN_X = 3, // compare to "(evt.type=open and evt.dir=<)" in a Falco rule
|
||||
PPME_SOCKET_CONNECT_X = 23, // compare to "(evt.type=connect and evt.dir=<)" in a Falco rule
|
||||
PPME_SYSCALL_CREAT_X = 59, // compare to "(evt.type=creat and evt.dir=<)" in a Falco rule
|
||||
PPME_SYSCALL_CLONE_20_X = 223, // compare to "(evt.type=clone and evt.dir=<)" in a Falco rule
|
||||
PPME_SOCKET_ACCEPT_5_X = 247, // compare to "(evt.type=accept and evt.dir=<)" in a Falco rule
|
||||
PPME_SYSCALL_EXECVE_19_X = 293, // compare to "(evt.type=execve and evt.dir=<)" in a Falco rule
|
||||
PPME_SYSCALL_OPENAT_2_X = 307, // compare to "(evt.type=openat and evt.dir=<)" in a Falco rule
|
||||
PPME_SYSCALL_OPENAT2_X = 327, // compare to "(evt.type=openat2 and evt.dir=<)" in a Falco rule
|
||||
PPME_SYSCALL_EXECVEAT_X = 331, // compare to "(evt.type=execveat and evt.dir=<)" in a Falco rule
|
||||
PPME_SYSCALL_CLONE3_X = 335, // compare to "(evt.type=clone3 and evt.dir=<)" in a Falco rule
|
||||
PPME_SYSCALL_OPEN_BY_HANDLE_AT_X = 337, // compare to "(evt.type=open_by_handle_at and evt.dir=<)" in a Falco rule
|
||||
PPME_SOCKET_ACCEPT4_6_X = 389, // compare to "(evt.type=accept4 and evt.dir=<)" in a Falco rule
|
||||
} ppm_event_code;
|
||||
```
|
||||
|
||||
### Behavior Profiles fields
|
||||
|
||||
Compare to [Supported Fields for Conditions and Outputs](https://falco.org/docs/reference/rules/supported-fields/).
|
||||
|
||||
The list below is complete, and no other fields from Falco can be used for the behavior profiles at the moment. The binary will error out if used incorrectly. Thank you for your patience.
|
||||
|
||||
| Supported Behavior Profile Field | Description |
|
||||
| --- | --- |
|
||||
|proc.exe|The first command-line argument (i.e., argv[0]), typically the executable name or a custom string as specified by the user. It is primarily obtained from syscall arguments, truncated after 4096 bytes, or, as a fallback, by reading /proc/PID/cmdline, in which case it may be truncated after 1024 bytes. This field may differ from the last component of proc.exepath, reflecting how command invocation and execution paths can vary.|
|
||||
|proc.pexe|The proc.exe (first command line argument argv[0]) of the parent process.|
|
||||
|proc.aexe|The proc.exe (first command line argument argv[0]) for a specific process ancestor. You can access different levels of ancestors by using indices. For example, proc.aexe[1] retrieves the proc.exe of the parent process, proc.aexe[2] retrieves the proc.exe of the grandparent process, and so on. The current process's proc.exe line can be obtained using proc.aexe[0]. When used without any arguments, proc.aexe is applicable only in filters and matches any of the process ancestors. For instance, you can use `proc.aexe endswith java` to match any process ancestor whose proc.exe ends with the term `java`.|
|
||||
|proc.exepath|The full executable path of a process, resolving to the canonical path for symlinks. This is primarily obtained from the kernel, or as a fallback, by reading /proc/PID/exe (in the latter case, the path is truncated after 1024 bytes). For eBPF drivers, due to verifier limits, path components may be truncated to 24 for legacy eBPF on kernel <5.2, 48 for legacy eBPF on kernel >=5.2, or 96 for modern eBPF.|
|
||||
|proc.pexepath|The proc.exepath (full executable path) of the parent process.|
|
||||
|proc.aexepath|The proc.exepath (full executable path) for a specific process ancestor. You can access different levels of ancestors by using indices. For example, proc.aexepath[1] retrieves the proc.exepath of the parent process, proc.aexepath[2] retrieves the proc.exepath of the grandparent process, and so on. The current process's proc.exepath line can be obtained using proc.aexepath[0]. When used without any arguments, proc.aexepath is applicable only in filters and matches any of the process ancestors. For instance, you can use `proc.aexepath endswith java` to match any process ancestor whose path ends with the term `java`.|
|
||||
|proc.name|The process name (truncated after 16 characters) generating the event (task->comm). Truncation is determined by kernel settings and not by Falco. This field is collected from the syscalls args or, as a fallback, extracted from /proc/PID/status. The name of the process and the name of the executable file on disk (if applicable) can be different if a process is given a custom name which is often the case for example for java applications.|
|
||||
|proc.pname|The proc.name truncated after 16 characters) of the process generating the event.|
|
||||
|proc.aname|The proc.name (truncated after 16 characters) for a specific process ancestor. You can access different levels of ancestors by using indices. For example, proc.aname[1] retrieves the proc.name of the parent process, proc.aname[2] retrieves the proc.name of the grandparent process, and so on. The current process's proc.name line can be obtained using proc.aname[0]. When used without any arguments, proc.aname is applicable only in filters and matches any of the process ancestors. For instance, you can use `proc.aname=bash` to match any process ancestor whose name is `bash`.|
|
||||
|proc.args|The arguments passed on the command line when starting the process generating the event excluding argv[0] (truncated after 4096 bytes). This field is collected from the syscalls args or, as a fallback, extracted from /proc/PID/cmdline.|
|
||||
|proc.cmdline|The concatenation of `proc.name + proc.args` (truncated after 4096 bytes) when starting the process generating the event.|
|
||||
|proc.pcmdline|The proc.cmdline (full command line (proc.name + proc.args)) of the parent of the process generating the event.|
|
||||
|proc.acmdline|The full command line (proc.name + proc.args) for a specific process ancestor. You can access different levels of ancestors by using indices. For example, proc.acmdline[1] retrieves the full command line of the parent process, proc.acmdline[2] retrieves the proc.cmdline of the grandparent process, and so on. The current process's full command line can be obtained using proc.acmdline[0]. When used without any arguments, proc.acmdline is applicable only in filters and matches any of the process ancestors. For instance, you can use `proc.acmdline contains base64` to match any process ancestor whose command line contains the term base64.|
|
||||
|proc.cmdnargs|The number of command line args (proc.args).|
|
||||
|proc.cmdlenargs|The total count of characters / length of the command line args (proc.args) combined excluding whitespaces between args.|
|
||||
|proc.exeline|The full command line, with exe as first argument (proc.exe + proc.args) when starting the process generating the event.|
|
||||
|proc.env|The environment variables of the process generating the event as concatenated string 'ENV_NAME=value ENV_NAME1=value1'. Can also be used to extract the value of a known env variable, e.g. proc.env[ENV_NAME].|
|
||||
|proc.cwd|The current working directory of the event.|
|
||||
|proc.tty|The controlling terminal of the process. 0 for processes without a terminal.|
|
||||
|proc.pid|The id of the process generating the event.|
|
||||
|proc.ppid|The pid of the parent of the process generating the event.|
|
||||
|proc.apid|The pid for a specific process ancestor. You can access different levels of ancestors by using indices. For example, proc.apid[1] retrieves the pid of the parent process, proc.apid[2] retrieves the pid of the grandparent process, and so on. The current process's pid can be obtained using proc.apid[0]. When used without any arguments, proc.apid is applicable only in filters and matches any of the process ancestors. For instance, you can use `proc.apid=1337` to match any process ancestor whose pid is equal to 1337.|
|
||||
|proc.vpid|The id of the process generating the event as seen from its current PID namespace.|
|
||||
|proc.pvpid|The id of the parent process generating the event as seen from its current PID namespace.|
|
||||
|proc.sid|The session id of the process generating the event.|
|
||||
|proc.sname|The name of the current process's session leader. This is either the process with pid=proc.sid or the eldest ancestor that has the same sid as the current process.|
|
||||
|proc.sid.exe|The first command line argument argv[0] (usually the executable name or a custom one) of the current process's session leader. This is either the process with pid=proc.sid or the eldest ancestor that has the same sid as the current process.|
|
||||
|proc.sid.exepath|The full executable path of the current process's session leader. This is either the process with pid=proc.sid or the eldest ancestor that has the same sid as the current process.|
|
||||
|proc.vpgid|The process group id of the process generating the event, as seen from its current PID namespace.|
|
||||
|proc.vpgid.name|The name of the current process's process group leader. This is either the process with proc.vpgid == proc.vpid or the eldest ancestor that has the same vpgid as the current process. The description of `proc.is_vpgid_leader` offers additional insights.|
|
||||
|proc.vpgid.exe|The first command line argument argv[0] (usually the executable name or a custom one) of the current process's process group leader. This is either the process with proc.vpgid == proc.vpid or the eldest ancestor that has the same vpgid as the current process. The description of `proc.is_vpgid_leader` offers additional insights.|
|
||||
|proc.vpgid.exepath|The full executable path of the current process's process group leader. This is either the process with proc.vpgid == proc.vpid or the eldest ancestor that has the same vpgid as the current process. The description of `proc.is_vpgid_leader` offers additional insights.|
|
||||
|proc.is_exe_writable|'true' if this process' executable file is writable by the same user that spawned the process.|
|
||||
|proc.is_exe_upper_layer|'true' if this process' executable file is in upper layer in overlayfs. This field value can only be trusted if the underlying kernel version is greater or equal than 3.18.0, since overlayfs was introduced at that time.|
|
||||
|proc.is_exe_from_memfd|'true' if the executable file of the current process is an anonymous file created using memfd_create() and is being executed by referencing its file descriptor (fd). This type of file exists only in memory and not on disk. Relevant to detect malicious in-memory code injection. Requires kernel version greater or equal to 3.17.0.|
|
||||
|proc.is_sid_leader|'true' if this process is the leader of the process session, proc.sid == proc.vpid. For host processes vpid reflects pid.|
|
||||
|proc.is_vpgid_leader|'true' if this process is the leader of the virtual process group, proc.vpgid == proc.vpid. For host processes vpgid and vpid reflect pgid and pid. Can help to distinguish if the process was 'directly' executed for instance in a tty (similar to bash history logging, `is_vpgid_leader` would be 'true') or executed as descendent process in the same process group which for example is the case when subprocesses are spawned from a script (`is_vpgid_leader` would be 'false').|
|
||||
|proc.exe_ino|The inode number of the executable file on disk. Can be correlated with fd.ino.|
|
||||
|proc.exe_ino.ctime|Last status change time of executable file (inode->ctime) as epoch timestamp in nanoseconds. Time is changed by writing or by setting inode information e.g. owner, group, link count, mode etc.|
|
||||
|proc.exe_ino.mtime|Last modification time of executable file (inode->mtime) as epoch timestamp in nanoseconds. Time is changed by file modifications, e.g. by mknod, truncate, utime, write of more than zero bytes etc. For tracking changes in owner, group, link count or mode, use proc.exe_ino.ctime instead.|
|
||||
|container.id|The truncated container ID (first 12 characters), e.g. 3ad7b26ded6d is extracted from the Linux cgroups by Falco within the kernel. Consequently, this field is reliably available and serves as the lookup key for Falco's synchronous or asynchronous requests against the container runtime socket to retrieve all other `'container.*'` information. One important aspect to be aware of is that if the process occurs on the host, meaning not in the container PID namespace, this field is set to a string called 'host'. In Kubernetes, pod sandbox container processes can exist where `container.id` matches `k8s.pod.sandbox_id`, lacking other 'container.*' details.|
|
||||
|fd.num|the unique number identifying the file descriptor.|
|
||||
|fd.name|FD full name. If the fd is a file, this field contains the full path. If the FD is a socket, this field contain the connection tuple.|
|
||||
|fd.directory|If the fd is a file, the directory that contains it.|
|
||||
|fd.filename|If the fd is a file, the filename without the path.|
|
||||
|fd.dev|device number (major/minor) containing the referenced file|
|
||||
|fd.ino|inode number of the referenced file|
|
||||
|fd.nameraw|FD full name raw. Just like fd.name, but only used if fd is a file path. File path is kept raw with limited sanitization and without deriving the absolute path.|
|
||||
|custom.proc.aname.lineage.join|[Incubating] String concatenate the process lineage to achieve better performance. It requires an argument to specify the maximum level of traversal, e.g. 'custom.proc.aname.lineage.join[7]'. This is a custom plugin specific field for the anomaly behavior profiles only. It may be dperecated in the future.|
|
||||
|custom.proc.aexe.lineage.join|[Incubating] String concatenate the process lineage to achieve better performance. It requires an argument to specify the maximum level of traversal, e.g. 'custom.proc.aexe.lineage.join[7]'. This is a custom plugin specific field for the anomaly behavior profiles only. It may be dperecated in the future.|
|
||||
|custom.proc.aexepath.lineage.join|[Incubating] String concatenate the process lineage to achieve better performance. It requires an argument to specify the maximum level of traversal, e.g. 'custom.proc.aexepath.lineage.join[7]'. This is a custom plugin specific field for the anomaly behavior profiles only. It may be dperecated in the future.|
|
||||
|custom.fd.name.part1|[Incubating] For fd related network events only. Part 1 as string of the ip tuple in the format 'ip:port', e.g '172.40.111.222:54321' given fd.name '172.40.111.222:54321->142.251.111.147:443'. It may be dperecated in the future.|
|
||||
|custom.fd.name.part2|[Incubating] For fd related network events only. Part 2 as string of the ip tuple in the format 'ip:port', e.g.'142.251.111.147:443' given fd.name '172.40.111.222:54321->142.251.111.147:443'. This is a custom plugin specific field for the anomaly behavior profiles only. It may be dperecated in the future.|
|
|
@ -1,26 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2024 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
message(STATUS "Fetching libs at 'https://github.com/falcosecurity/libs.git'")
|
||||
|
||||
FetchContent_Declare(
|
||||
libs
|
||||
GIT_REPOSITORY https://github.com/falcosecurity/libs.git
|
||||
GIT_TAG 273299c5832ab7efa6a93547f7c3bd55706b135c
|
||||
CONFIGURE_COMMAND "" BUILD_COMMAND "")
|
||||
|
||||
FetchContent_MakeAvailable(libs)
|
||||
set(LIBS_INCLUDE "${libs_SOURCE_DIR}")
|
||||
set(LIBS_DIR "${libs_SOURCE_DIR}")
|
||||
message(STATUS "Using libs include at '${LIBS_INCLUDE}'")
|
|
@ -1,27 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2024 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
message(
|
||||
STATUS
|
||||
"Fetching plugin-sdk-cpp at 'https://github.com/falcosecurity/plugin-sdk-cpp.git'"
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
plugin-sdk-cpp
|
||||
GIT_REPOSITORY https://github.com/falcosecurity/plugin-sdk-cpp.git
|
||||
GIT_TAG 1c46ba02e8e9fe30a8362a54e99a6c3c804661f6)
|
||||
|
||||
FetchContent_MakeAvailable(plugin-sdk-cpp)
|
||||
set(PLUGIN_SDK_INCLUDE "${plugin-sdk-cpp_SOURCE_DIR}/include")
|
||||
message(STATUS "Using plugin-sdk-cpp include at '${PLUGIN_SDK_INCLUDE}'")
|
|
@ -1,31 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2024 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
message(
|
||||
STATUS
|
||||
"Fetching xxhash at 'https://raw.githubusercontent.com/Cyan4973/xxHash/v0.8.2/xxhash.h'"
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
# BSD 2-Clause License
|
||||
xxhash
|
||||
URL "https://raw.githubusercontent.com/Cyan4973/xxHash/v0.8.2/xxhash.h"
|
||||
URL_HASH SHA256=be275e9db21a503c37f24683cdb4908f2370a3e35ab96e02c4ea73dc8e399c43
|
||||
DOWNLOAD_NAME "xxhash.h"
|
||||
DOWNLOAD_NO_EXTRACT TRUE
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(xxhash)
|
||||
set(XXHASH_INCLUDE "${xxhash_SOURCE_DIR}")
|
||||
message(STATUS "Using xxhash include at '${XXHASH_INCLUDE}'")
|
|
@ -1,228 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2024 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xxhash_ext.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
/*
|
||||
CountMinSketch Powered Probabilistic Counting and Filtering
|
||||
Falco Proposal: https://github.com/falcosecurity/falco/blob/master/proposals/20230620-anomaly-detection-framework.md
|
||||
*/
|
||||
|
||||
namespace plugin::anomalydetection::num
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class cms
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<std::unique_ptr<T[]>[]> sketch;
|
||||
uint64_t d_; // d / Rows / number of hash functions
|
||||
uint64_t w_; // w / Cols / number of buckets
|
||||
double gamma_; // Error probability (e.g. 0.001)
|
||||
double eps_; // Relative error (e.g. 0.0001)
|
||||
|
||||
public:
|
||||
static uint64_t calculate_d_rows_from_gamma(double gamma)
|
||||
{
|
||||
// -> determine Rows / number of hash functions
|
||||
return static_cast<uint64_t>(std::ceil(std::log(1.0 / gamma)));
|
||||
}
|
||||
|
||||
static double calculate_gamma_rows_from_d(uint64_t d)
|
||||
{
|
||||
// -> reverse calculate error probability from Rows / number of hash functions
|
||||
return 1.0 / std::exp(d);
|
||||
}
|
||||
|
||||
static uint64_t calculate_w_cols_buckets_from_eps(double eps)
|
||||
{
|
||||
// -> determine Cols / number of buckets
|
||||
return static_cast<uint64_t>(std::ceil(std::exp(1) / eps));
|
||||
}
|
||||
|
||||
static double calculate_eps_cols_buckets_from_w(uint64_t w)
|
||||
{
|
||||
// -> reverse calculate relative error from Cols / number of buckets
|
||||
return std::exp(1) / w;
|
||||
}
|
||||
|
||||
cms(double gamma, double eps)
|
||||
{
|
||||
d_ = calculate_d_rows_from_gamma(gamma); // -> determine Rows / number of hash functions
|
||||
w_ = calculate_w_cols_buckets_from_eps(eps); // -> determine Cols / number of buckets
|
||||
gamma_ = gamma;
|
||||
eps_ = eps;
|
||||
sketch = std::make_unique<std::unique_ptr<T[]>[]>(d_);
|
||||
for (uint64_t i = 0; i < d_; ++i)
|
||||
{
|
||||
sketch[i] = std::make_unique<T[]>(w_);
|
||||
std::fill(sketch[i].get(), sketch[i].get() + w_, static_cast<T>(0)); // Init to 0
|
||||
}
|
||||
}
|
||||
|
||||
// Overloaded constructor
|
||||
cms(uint64_t d, uint64_t w)
|
||||
{
|
||||
d_ = d;
|
||||
w_ = w;
|
||||
gamma_ = calculate_gamma_rows_from_d(d); // -> reverse calculate error probability from Rows / number of hash functions
|
||||
eps_ = calculate_eps_cols_buckets_from_w(w); // -> reverse calculate relative error from Cols / number of buckets
|
||||
sketch = std::make_unique<std::unique_ptr<T[]>[]>(d_);
|
||||
for (uint64_t i = 0; i < d_; ++i)
|
||||
{
|
||||
sketch[i] = std::make_unique<T[]>(w_);
|
||||
std::fill(sketch[i].get(), sketch[i].get() + w_, static_cast<T>(0)); // Init to 0
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
// Reset data structure
|
||||
for (uint64_t i = 0; i < d_; ++i)
|
||||
{
|
||||
std::fill(sketch[i].get(), sketch[i].get() + w_, static_cast<T>(0));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t hash_XXH3_seed(std::string value, uint64_t seed) const
|
||||
{
|
||||
// using https://raw.githubusercontent.com/Cyan4973/xxHash/v0.8.2/xxhash.h
|
||||
// Requirement: Need fast and reliable independent hash functions.
|
||||
uint64_t hash = XXH3_64bits_withSeed(value.c_str(), value.size(), seed);
|
||||
return hash;
|
||||
}
|
||||
|
||||
void update(std::string value, T count)
|
||||
{
|
||||
if (value.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Update counts for each hash function.
|
||||
// Note: d is typically very small (e.g. < 10)
|
||||
for (uint64_t seed = 0; seed < d_; ++seed)
|
||||
{
|
||||
// Map the hash value to an index of the current sketch Row by taking the modulo of the hash value, where w is the number of buckets.
|
||||
// Simply loop over d, which is the number of hash functions, to obtain a seed in order to use independent hash functions for each Row.
|
||||
sketch[seed][hash_XXH3_seed(value, seed) % w_] += count;
|
||||
}
|
||||
}
|
||||
|
||||
T update_estimate(std::string value, T count) const
|
||||
{
|
||||
if (value.empty())
|
||||
{
|
||||
return T();
|
||||
}
|
||||
std::vector<T> estimates;
|
||||
// Same as the update function, but also returns the minimum count as an estimate.
|
||||
// Note: d is typically very small (e.g. < 10)
|
||||
for (uint64_t seed = 0; seed < d_; ++seed)
|
||||
{
|
||||
uint64_t index = hash_XXH3_seed(value, seed) % w_;
|
||||
sketch[seed][index] += count;
|
||||
estimates.push_back(sketch[seed][index]);
|
||||
}
|
||||
auto min_element = std::min_element(estimates.begin(), estimates.end());
|
||||
return min_element != estimates.end() ? *min_element : T();
|
||||
}
|
||||
|
||||
T estimate(std::string value) const
|
||||
{
|
||||
if (value.empty())
|
||||
{
|
||||
return T();
|
||||
}
|
||||
std::vector<T> estimates;
|
||||
// Return the minimum count across hash functions as an estimate.
|
||||
// Note: d is typically very small (e.g. < 10)
|
||||
for (uint64_t seed = 0; seed < d_; ++seed)
|
||||
{
|
||||
uint64_t index = hash_XXH3_seed(value, seed) % w_;
|
||||
estimates.push_back(sketch[seed][index]);
|
||||
}
|
||||
auto min_element = std::min_element(estimates.begin(), estimates.end());
|
||||
return min_element != estimates.end() ? *min_element : T();
|
||||
}
|
||||
|
||||
T get_item(uint64_t row, uint64_t col) const
|
||||
{
|
||||
if (row >= 0 && row < d_ && col >= 0 && col < w_)
|
||||
{
|
||||
return sketch[row][col];
|
||||
} else
|
||||
{
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_size_bytes() const
|
||||
{
|
||||
return d_ * w_ * sizeof(T);
|
||||
}
|
||||
|
||||
static size_t get_size_bytes(uint64_t d, uint64_t w)
|
||||
{
|
||||
return d * w * sizeof(T);
|
||||
}
|
||||
|
||||
std::pair<uint64_t, uint64_t> get_dimensions() const
|
||||
{
|
||||
return std::make_pair(d_, w_);
|
||||
}
|
||||
|
||||
// Return Rows / number of hash functions
|
||||
uint64_t get_d() const
|
||||
{
|
||||
return d_;
|
||||
}
|
||||
|
||||
// Return Cols / number of buckets
|
||||
uint64_t get_w() const
|
||||
{
|
||||
return w_;
|
||||
}
|
||||
|
||||
// Return error probability
|
||||
double get_gamma() const
|
||||
{
|
||||
return gamma_;
|
||||
}
|
||||
|
||||
// Return relative error
|
||||
double get_eps() const
|
||||
{
|
||||
return eps_;
|
||||
}
|
||||
|
||||
cms(cms&&) noexcept = default;
|
||||
cms(const cms&) = default;
|
||||
cms& operator=(cms&&) noexcept = default;
|
||||
cms& operator=(const cms&) = default;
|
||||
cms() = delete;
|
||||
};
|
||||
|
||||
} // namespace plugin::anomalydetection::num
|
|
@ -1,19 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2024 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#define XXH_INLINE_ALL
|
||||
#include <xxhash.h>
|
File diff suppressed because it is too large
Load Diff
|
@ -1,228 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2024 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "num/cms.h"
|
||||
#include "plugin_consts.h"
|
||||
#include "plugin_utils.h"
|
||||
#include "plugin_mutex.h"
|
||||
#include "plugin_thread_manager.h"
|
||||
#include "plugin_sinsp_filterchecks.h"
|
||||
|
||||
#include <falcosecurity/sdk.h>
|
||||
#include <driver/ppm_events_public.h> // Temporary workaround to avoid redefining syscalls PPME events and risking being out of sync
|
||||
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <sstream>
|
||||
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#define PPM_AT_FDCWD -100
|
||||
#define SECOND_TO_NS 1000000000ULL
|
||||
|
||||
struct sinsp_param
|
||||
{
|
||||
uint16_t param_len;
|
||||
uint8_t* param_pointer;
|
||||
};
|
||||
|
||||
class anomalydetection
|
||||
{
|
||||
public:
|
||||
anomalydetection() : m_thread_manager() {}
|
||||
|
||||
// Keep this aligned with `get_fields`
|
||||
enum anomalydetection_fields
|
||||
{
|
||||
ANOMALYDETECTION_COUNT_MIN_SKETCH_COUNT = 0,
|
||||
ANOMALYDETECTION_COUNT_MIN_SKETCH_BEHAVIOR_PROFILE_CONCAT_STR,
|
||||
ANOMALYDETECTION_FALCO_DURATION_NS,
|
||||
ANOMALYDETECTION_FIELD_MAX
|
||||
};
|
||||
|
||||
//////////////////////////
|
||||
// General plugin API
|
||||
//////////////////////////
|
||||
|
||||
virtual ~anomalydetection() = default;
|
||||
|
||||
std::string get_name() { return PLUGIN_NAME; }
|
||||
|
||||
std::string get_version() { return PLUGIN_VERSION; }
|
||||
|
||||
std::string get_description() { return PLUGIN_DESCRIPTION; }
|
||||
|
||||
std::string get_contact() { return PLUGIN_CONTACT; }
|
||||
|
||||
std::string get_required_api_version()
|
||||
{
|
||||
return PLUGIN_REQUIRED_API_VERSION;
|
||||
}
|
||||
|
||||
falcosecurity::init_schema get_init_schema();
|
||||
|
||||
void parse_init_config(nlohmann::json& config_json);
|
||||
|
||||
bool init(falcosecurity::init_input& in);
|
||||
|
||||
// todo
|
||||
// void destroy();
|
||||
|
||||
std::string get_last_error() { return m_lasterr; }
|
||||
|
||||
static void log_error(std::string err_mess);
|
||||
|
||||
//////////////////////////
|
||||
// Extract capability
|
||||
//////////////////////////
|
||||
|
||||
// required; standard plugin API
|
||||
std::vector<std::string> get_extract_event_sources()
|
||||
{
|
||||
return {"syscall"};
|
||||
}
|
||||
|
||||
// required; standard plugin API
|
||||
std::vector<falcosecurity::field_info> get_fields();
|
||||
|
||||
// required; standard plugin API
|
||||
bool extract(const falcosecurity::extract_fields_input& in);
|
||||
|
||||
//////////////////////////
|
||||
// Parse capability
|
||||
//////////////////////////
|
||||
|
||||
// required; standard plugin API
|
||||
std::vector<std::string> get_parse_event_sources()
|
||||
{
|
||||
return {"syscall"};
|
||||
}
|
||||
|
||||
// required; standard plugin API
|
||||
std::vector<falcosecurity::event_type> get_parse_event_types()
|
||||
{
|
||||
std::vector<falcosecurity::event_type> event_types;
|
||||
// Temporary workaround
|
||||
for (int i = PPME_GENERIC_E; i <= PPM_EVENT_MAX; ++i)
|
||||
{
|
||||
event_types.push_back(static_cast<falcosecurity::event_type>(i));
|
||||
}
|
||||
return event_types;
|
||||
}
|
||||
|
||||
// required; standard plugin API
|
||||
bool parse_event(const falcosecurity::parse_event_input& in);
|
||||
|
||||
// Custom helper functions within event parsing
|
||||
bool extract_filterchecks_concat_profile(const falcosecurity::event_reader &evt, const falcosecurity::table_reader &tr, const std::vector<plugin_sinsp_filterchecks_field>& fields, std::string& behavior_profile_concat_str);
|
||||
std::string extract_filterchecks_evt_params_fallbacks(const falcosecurity::event_reader &evt, const plugin_sinsp_filterchecks_field& field, const std::string& cwd = "");
|
||||
|
||||
private:
|
||||
|
||||
// Manages plugin side threads, such as resetting the count min sketch data structures
|
||||
ThreadManager m_thread_manager;
|
||||
|
||||
// Epoch of Falco agent run start, re-creates libs agent_info->start_ts_epoch info
|
||||
uint64_t m_falco_start_ts_epoch_ns;
|
||||
|
||||
/* Note: While we have set the stage for supporting multiple algorithms in this plugin,
|
||||
the class is currently designed with direct members specific to the count_min_sketch use case.
|
||||
This will be refactored and refined in the future.
|
||||
*/
|
||||
bool m_count_min_sketch_enabled = false;
|
||||
uint32_t m_n_sketches = 0;
|
||||
std::vector<std::vector<double>> m_gamma_eps;
|
||||
std::vector<std::vector<uint64_t>> m_rows_cols; // If set supersedes m_gamma_eps
|
||||
std::vector<std::vector<plugin_sinsp_filterchecks_field>> m_behavior_profiles_fields;
|
||||
std::vector<std::unordered_set<ppm_event_code>> m_behavior_profiles_event_codes;
|
||||
std::vector<uint64_t> m_reset_timers;
|
||||
|
||||
// Plugin managed state table specific to the count_min_sketch use case
|
||||
plugin_anomalydetection::Mutex<std::vector<std::shared_ptr<plugin::anomalydetection::num::cms<uint64_t>>>> m_count_min_sketches;
|
||||
|
||||
// required; standard plugin API
|
||||
std::string m_lasterr;
|
||||
// required; standard plugin API; accessor to falcosecurity/libs' thread table
|
||||
falcosecurity::table m_thread_table;
|
||||
|
||||
/* Subtables */
|
||||
falcosecurity::table_field m_args; ///< args subtable
|
||||
falcosecurity::table_field m_env; ///< env variables subtable
|
||||
falcosecurity::table_field m_fds; ///< fd subtable
|
||||
|
||||
/* proc related */
|
||||
falcosecurity::table_field m_tid; ///< The id of this thread
|
||||
falcosecurity::table_field m_pid; ///< The id of the process containing this thread. In single thread threads, this is equal to tid.
|
||||
falcosecurity::table_field m_ptid; ///< The id of the process that started this thread.
|
||||
falcosecurity::table_field m_sid; ///< The session id of the process containing this thread.
|
||||
falcosecurity::table_field m_comm; ///< Command name (e.g. "top")
|
||||
falcosecurity::table_field m_exe; ///< argv[0] (e.g. "sshd: user@pts/4")
|
||||
falcosecurity::table_field m_exepath; ///< full executable path
|
||||
falcosecurity::table_field m_exe_writable;
|
||||
falcosecurity::table_field m_exe_upper_layer; ///< True if the executable file belongs to upper layer in overlayfs
|
||||
falcosecurity::table_field m_exe_from_memfd; ///< True if the executable is stored in fileless memory referenced by memfd
|
||||
falcosecurity::table_field m_exe_ino;
|
||||
falcosecurity::table_field m_exe_ino_ctime;
|
||||
falcosecurity::table_field m_exe_ino_mtime;
|
||||
// falcosecurity::table_field m_cap_permitted; // todo fix/expose via plugin API
|
||||
// falcosecurity::table_field m_cap_inheritable; // todo fix/expose via plugin API
|
||||
// falcosecurity::table_field m_cap_effective; // todo fix/expose via plugin API
|
||||
falcosecurity::table_field m_args_value; ///< Value entry to command line arguments (e.g. "-d1") from the args array
|
||||
falcosecurity::table_field m_env_value; ///< Value entry
|
||||
falcosecurity::table_field m_group; ///< group infos
|
||||
falcosecurity::table_field m_vtid; ///< The virtual id of this thread.
|
||||
falcosecurity::table_field m_vpid; ///< The virtual id of the process containing this thread. In single thread threads, this is equal to vtid.
|
||||
falcosecurity::table_field m_vpgid; // The virtual process group id, as seen from its pid namespace
|
||||
falcosecurity::table_field m_tty; ///< Number of controlling terminal
|
||||
falcosecurity::table_field m_cwd; ///< current working directory
|
||||
|
||||
/* user related */
|
||||
// Not available until the next libs plugins API expansion
|
||||
// falcosecurity::table_field m_uid; ///< user uid
|
||||
// falcosecurity::table_field m_user; ///< user infos
|
||||
// falcosecurity::table_field m_loginuid; ///< auid
|
||||
// falcosecurity::table_field m_loginuser; ///< loginuser infos (auid)
|
||||
|
||||
/* fd related */
|
||||
// falcosecurity::table_field m_fd_type_value; // todo fix/expose via plugin API
|
||||
falcosecurity::table_field m_fd_openflags_value;
|
||||
// falcosecurity::table_field m_fd_sockinfo_value; // todo fix/expose via plugin API
|
||||
falcosecurity::table_field m_fd_name_value;
|
||||
falcosecurity::table_field m_fd_nameraw_value;
|
||||
falcosecurity::table_field m_fd_oldname_value;
|
||||
falcosecurity::table_field m_fd_flags_value;
|
||||
falcosecurity::table_field m_fd_dev_value;
|
||||
falcosecurity::table_field m_fd_mount_id_value;
|
||||
falcosecurity::table_field m_fd_ino_value;
|
||||
falcosecurity::table_field m_fd_pid_value;
|
||||
// falcosecurity::table_field m_fd_fd_value; // todo fix/expose via plugin API
|
||||
|
||||
/* container related */
|
||||
falcosecurity::table_field m_container_id; ///< heuristic-based container id
|
||||
|
||||
/* Custom write/read fields*/
|
||||
falcosecurity::table_field m_lastevent_fd_field; // todo fix/expose via plugin API
|
||||
};
|
||||
|
||||
// required; standard plugin API
|
||||
FALCOSECURITY_PLUGIN(anomalydetection);
|
||||
FALCOSECURITY_PLUGIN_FIELD_EXTRACTION(anomalydetection);
|
||||
FALCOSECURITY_PLUGIN_EVENT_PARSING(anomalydetection);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue