Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ IMAGE?=quay.io/kubescape/$(BINARY_NAME)
# GADGETS are pulled unmodified from upstream IG. trace_open is intentionally NOT
# here: it is vendored and built from source (see BUILT_GADGETS) so the fpath
# resolver can resolve relative opens against their dirfd/cwd.
GADGETS=advise_seccomp trace_capabilities trace_dns trace_exec
GADGETS=advise_seccomp audit_seccomp trace_capabilities trace_dns trace_exec
VERSION=v0.48.1
KUBESCAPE_GADGETS=bpf exit fork hardlink http iouring_new iouring_old kmod network ptrace randomx ssh symlink unshare
# BUILT_GADGETS are vendored under pkg/ebpf/gadgets and built under their full
Expand Down
50 changes: 50 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
_ "net/http/pprof"
"os"
"os/signal"
stdruntime "runtime"
"strings"
"syscall"
"time"
Expand All @@ -17,6 +18,7 @@ import (
"github.com/goradd/maps"
"github.com/grafana/pyroscope-go"

contribseccomp "github.com/containerd/containerd/contrib/seccomp"
igconfig "github.com/inspektor-gadget/inspektor-gadget/pkg/config"
containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection"
iglogger "github.com/inspektor-gadget/inspektor-gadget/pkg/logger"
Expand Down Expand Up @@ -62,7 +64,9 @@ import (
"github.com/kubescape/node-agent/pkg/rulemanager/rulecooldown"
"github.com/kubescape/node-agent/pkg/rulemanager/rulecreator"
"github.com/kubescape/node-agent/pkg/rulemanager/ruleswatcher"
"github.com/kubescape/node-agent/pkg/sandboxpolicy"
sandboxintegration "github.com/kubescape/node-agent/pkg/sandboxpolicy/integration"
sandboxseccomp "github.com/kubescape/node-agent/pkg/sandboxpolicy/seccomp"
"github.com/kubescape/node-agent/pkg/sbommanager"
sbommanagerv1 "github.com/kubescape/node-agent/pkg/sbommanager/v1"
sbomscanner "github.com/kubescape/node-agent/pkg/sbomscanner/v1"
Expand All @@ -73,6 +77,7 @@ import (
"github.com/kubescape/node-agent/pkg/validator"
"github.com/kubescape/node-agent/pkg/watcher/dynamicwatcher"
"github.com/kubescape/node-agent/pkg/watcher/seccompprofilewatcher"
specs "github.com/opencontainers/runtime-spec/specs-go"
goruntime "go.opentelemetry.io/contrib/instrumentation/runtime"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand Down Expand Up @@ -570,6 +575,7 @@ func main() {
defer mainHandler.Stop()
}

var sandboxController *sandboxpolicy.Controller
if cfg.EnableSandboxPolicy {
// Enforcement is independent of observer/runtime-detection switches. The
// service rejects unavailable predicates/bindings rather than weakening them.
Expand All @@ -586,6 +592,7 @@ func main() {
logger.L().Ctx(ctx).Fatal("creating sandbox policy service", helpers.Error(sandboxErr))
}
dWatcher.AddAdaptor(sandboxService)
sandboxController = sandboxService.Controller
if sandboxErr = sandboxService.Start(ctx); sandboxErr != nil {
logger.L().Ctx(ctx).Fatal("starting sandbox policy service", helpers.Error(sandboxErr))
}
Expand All @@ -598,6 +605,14 @@ func main() {
}()
}

if cfg.EnableSandboxSeccomp {
// The seccomp layer needs no BPF LSM. A failure here disables only this
// layer; the rest of node-agent keeps running.
if err := startSandboxSeccomp(ctx, cfg, k8sClient, k8sObjectCache, sandboxController, dWatcher, thirdPartyTracers.ThirdPartyEventReceivers); err != nil {
logger.L().Ctx(ctx).Error("sandbox seccomp layer disabled", helpers.Error(err))
}
}

// start watching
dWatcher.Start(ctx)
defer dWatcher.Stop(ctx)
Expand Down Expand Up @@ -656,3 +671,38 @@ func resolveOwnContainerID(ctx context.Context, k8sClient *k8sinterface.Kubernet
helpers.String("pod", podName), helpers.String("namespace", namespace))
return "", ""
}

func startSandboxSeccomp(ctx context.Context, cfg config.Config, k8sClient *k8sinterface.KubernetesApi, pods *k8scache.K8sObjectCacheImpl, controller *sandboxpolicy.Controller, dWatcher *dynamicwatcher.WatchHandler, receivers sandboxseccomp.Receivers) error {
profilesDir, err := seccompmanagerv1.ProfilesDir()
if err != nil {
return err
}
layer, err := sandboxseccomp.NewService(sandboxseccomp.Options{
Dynamic: k8sClient.GetDynamicClient(), Kubernetes: k8sClient.GetKubernetesClient(), Pods: pods.GetPod,
NodeName: cfg.NodeName, AgentNamespace: cfg.NamespaceName, NRISocket: cfg.SandboxSeccompNRISocket,
ProfilesDir: profilesDir, Arch: stdruntime.GOARCH,
RuntimeDefault: func(capabilities []string) *specs.LinuxSeccomp {
return contribseccomp.DefaultProfile(&specs.Spec{Process: &specs.Process{Capabilities: &specs.LinuxCapabilities{Bounding: capabilities}}})
},
ExecEnforcement: controller != nil,
Contributes: controller != nil,
Writer: &sandboxpolicy.DynamicStatusWriter{Client: k8sClient.GetDynamicClient()},
Receivers: receivers,
OnError: func(err error) { logger.L().Ctx(ctx).Warning("sandbox seccomp layer", helpers.Error(err)) },
})
if err != nil {
return err
}
// audit_seccomp events feed the layer, which forwards attributed verdicts
set, ok := receivers.Load(utils.AuditSeccompEventType)
if !ok {
set = mapset.NewSet[containerwatcher.GenericEventReceiver]()
receivers.Set(utils.AuditSeccompEventType, set)
}
set.Add(layer)
if controller != nil {
controller.AddStatusContributor(layer)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High — a startup failure can report an unenforced privilege policy as Ready. The contributor is registered before Start; if its node GET fails (for example, a transient API error), Start returns without starting either loop, but the caller only logs and continues. The empty contributor suppresses the seccompDisabled fallback in status.go:100-104, and Contribute returns no pending rules or conditions. With the exec controller enabled, privilege policies can therefore report Ready while no seccomp profiles are delivered. Register only after successful startup or expose a persistent failure condition, and test the failed-start path.

}
dWatcher.AddAdaptor(layer)
return layer.Start(ctx)
}
135 changes: 135 additions & 0 deletions docs/features/sandbox-seccomp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# SandboxPolicy seccomp layer (experimental)

Enforces the syscall rules of a SandboxPolicy `privilege` section with seccomp.
It is independent of the exec enforcement in `sandbox-policy.md`: it needs no BPF
LSM, and it runs with or without `sandboxPolicyEnabled`.

## Configuration

Disabled by default:

```json
{"sandboxSeccompEnabled": false, "sandboxSeccompNRISocket": "/var/run/nri/nri.sock"}
```

The agent needs the NRI socket mounted at that path, write access to the
kubelet seccomp directory (the existing `HOST_ROOT`/`KUBELET_ROOT` mount used by
the seccomp manager), and get/list on pods, namespaces, nodes, SandboxPolicy and
ClusterSandboxPolicy, plus SandboxPolicyNodeStatus writes. A start-up failure is
logged and disables only this layer.

## What it compiles

Only rules whose target is `syscall` (with optional `flags`). Capability,
`mountFsType` and `pathClass` targets belong to other hooks and are reported, not
dropped. Every other rule shape seccomp cannot express is reported the same way:
actor predicates, `flags` on `setns` (nstype 0 joins any namespace), and `clone`
without flags (it would deny every process creation).

- A CRD syscall name expands to its whole kernel family: `mount` also denies
`fsopen`, `fsconfig`, `fsmount`, `fspick`, `move_mount`, `open_tree` and
`mount_setattr`; `setuid` also denies `setreuid`, `setresuid` and `setfsuid`;
`keyctl`, `kexec_load`, `mknod` and `setgid` likewise.
- `flags` on `clone`/`unshare` become one masked-equal match per namespace bit.
- `clone3` passes its flags in memory, out of seccomp's reach. When `clone` has
an enforced flag rule, `clone3` is denied with `ENOSYS`, so glibc falls back to
`clone` where the flag rule applies. `EPERM` would make glibc fail every new
thread ("can't start new thread"); this was reproduced with glibc 2.41.
- `enforce` → `SCMP_ACT_ERRNO` (`EPERM`) and `SECCOMP_FILTER_FLAG_LOG`;
`audit` → `SCMP_ACT_LOG`. Across policies, deny wins and enforce wins over audit.
- A section `default: deny` denies the CRD syscall vocabulary, except syscalls
with an allow rule. For `clone`/`unshare` it means "with any namespace flag". A
syscall with an actor- or flag-scoped allow is not denied by seccomp: seccomp
cannot scope the exception, so another layer must.
- When the exec controller runs, a pod with an enforced exec policy also gets the
root barrier exec enforcement relies on (`chroot`, `pivot_root`, `setns`,
`unshare`, `clone3`, and the `CLONE_NEWUSER`/`CLONE_NEWNS` bits of `clone`),
reported as rule `exec-root-barrier`. Audit policies do not get it.

## Base profile

SandboxPolicy only adds denials to the profile the container would run anyway:

- The runtime's report wins. containerd reports the profile kind to NRI and, for
RuntimeDefault, the exact profile (verified on containerd 2.3.4). That exact
profile is the base, with denied syscalls removed from its allow entries and
flag denials narrowing them. Audited syscalls the base allows are logged,
never silently allowed; syscalls the base already denies stay denied.
- `Unconfined`: default allow plus the denials. Native and compat ABIs are both
listed (x86_64/x86/x32, aarch64/arm), so 32-bit binaries are filtered, not
killed; `setuid` and `setgid` include their `*32` variants.
- Without a runtime report and without a profile in the pod spec, the kubelet
may still apply RuntimeDefault (`seccompDefault`). The layer does not inject
then, and reports the container. Fallback files for such pods are built on
RuntimeDefault, the stricter choice.
- A container's own `Localhost` profile and privileged containers are left
alone and reported.

## Delivery

1. **NRI (preferred).** The layer registers as NRI plugin `50-kubescape-sandbox`
and sets the profile in `CreateContainer`. It also adds the annotation
`kubescape.io/sandbox-seccomp` with the profile revision, which the runtime
keeps, so a restarted agent knows which containers already run which profile.
Seccomp adjustment needs containerd ≥ 2.2.0 or CRI-O ≥ 1.34.0 with NRI enabled
(the default since containerd 2.0). An older runtime may accept the adjustment
and drop the profile, so the plugin checks the runtime version at registration
and stays on fallback files otherwise. The layer never fails container
creation: a container it cannot protect is reported instead. The creation hook
reads caches, with lookups bounded well under NRI's 2 s request timeout.
2. **Fallback file.** Without NRI, the profile is written to
`<kubelet>/seccomp/kubescape-sandbox/<base>-<revision>.json` (`rd-` or `uc-`). The
layer never changes a pod spec; a pod opts in by setting
`seccompProfile: {type: Localhost, localhostProfile: kubescape-sandbox/<file>}`.
Files no pod uses are removed after 10 minutes.

## Applies on restart

The kernel cannot remove or loosen a seccomp filter of a running process, so a
profile reaches a container only when it is created. Every 5 s, and on policy
watch events, the layer compares each container's injected revision with the
desired one. Policies are listed after a watch event and every minute; without
NRI, the node's pods are listed every 30 s. Rules of containers that differ are listed in the policy's node
report under `status.appliesOnRestart`, with the reasons in the
`SeccompAppliesOnRestart` condition, for example "2 container(s): policy changed
after the container started". Rules seccomp cannot express are listed in the
`SeccompRulesNotEnforced` condition. With exec enforcement enabled, these are
added to the exec controller's report; otherwise the layer writes the report
itself with tier `seccomp-only`. Either way, Ready is False while any rule waits
for a restart or is not enforced. With the layer disabled, a policy with a `privilege`
section reports `PrivilegeNotEnforced` and is not Ready. A restart button in the UI is a possible
follow-up; the operator's `operatorAction` framework could carry it.

## Events

The `audit_seccomp` IG gadget (added to `tracers.tar`, enabled with this layer)
reports the kernel's seccomp log records. The layer keeps only records of
profiles it injected, drops runc's own `open_tree` records (runc retries a denied
`open_tree` with the old mount API during `kubectl exec`), attributes the syscall to the policy
rules, and dispatches a `seccomp.Verdict` to receivers registered under
`utils.SyscallAuthorizationEventType` (`syscallAuthorization`), either as
`seccomp.VerdictReceiver` or as `EventReceiver`. Like `execAuthorization`, this is
an authorization record, not a syscall observation.

Attribution uses the rules of the revision injected into that container and
needs no API calls. `SECCOMP_FILTER_FLAG_LOG` logs every ERRNO decision of the
profile, including the base's own denials and the `clone3` `ENOSYS` that glibc
hits on each new thread; those records are dropped here, but the kernel still
writes them. The volume on thread-heavy workloads is not measured yet.

The kernel record carries no arguments. A match on a flag rule is therefore a
candidate, marked `MatchesComplete=false`. The wire name of the exported event
is proposed in the private exporter, not here.

## Verification

Unit tests cover compilation, profile merging on both bases, pending reasons,
fallback files and event attribution. A lab run on kind (Kubernetes 1.36,
containerd 2.3.4, arm64, kernel 6.8) confirmed: NRI injection into a selected
pod only; `unshare -U` and `mount` denied with `EPERM` in enforce and logged in
audit; threads still working; `kubectl exec` still working; the RuntimeDefault
merge keeping the runtime's own default-deny profile; compat ABIs and syscall
names unknown on arm64 accepted by runc; pending reasons after a policy change and after a
layer restart (revisions recovered from the annotation); and the fallback file
protecting an opted-in pod. The `audit_seccomp` tracer path inside a full
node-agent deployment was not run in the lab.
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ require (
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/nri v0.11.0 // indirect
github.com/containerd/nri v0.10.0
github.com/containerd/platforms v1.0.0-rc.2 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
Expand Down Expand Up @@ -307,6 +307,7 @@ require (
github.com/klauspost/compress v1.19.1 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/knqyf263/go-plugin v0.9.0 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mackerelio/go-osstat v0.2.5 // indirect
Expand Down Expand Up @@ -401,6 +402,7 @@ require (
github.com/subosito/gotenv v1.6.0 // indirect
github.com/sylabs/sif/v2 v2.24.0 // indirect
github.com/sylabs/squashfs v1.0.6 // indirect
github.com/tetratelabs/wazero v1.11.0 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/uptrace/opentelemetry-go-extra/otelutil v0.4.0 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,8 @@ github.com/containerd/go-runc v1.1.0/go.mod h1:xJv2hFF7GvHtTJd9JqTS2UVxMkULUYw4J
github.com/containerd/imgcrypt v1.1.8/go.mod h1:x6QvFIkMyO2qGIY2zXc88ivEzcbgvLdWjoZyGqDap5U=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/nri v0.10.0 h1:bt2NzfvlY6OJE0i+fB5WVeGQEycxY7iFVQpEbh7J3Go=
github.com/containerd/nri v0.10.0/go.mod h1:5VyvLa/4uL8FjyO8nis1UjbCutXDpngil17KvBSL6BU=
github.com/containerd/nri v0.11.0 h1:26mcQwNG58AZn0YkOrlJQ0yxQVmyZooflnVWJTqQrqQ=
github.com/containerd/nri v0.11.0/go.mod h1:bjGTLdUA58WgghKHg8azFMGXr05n1wDHrt3NSVBHiGI=
github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4=
Expand Down Expand Up @@ -1197,6 +1199,7 @@ github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f/go.mod h1:q59u9px8b7UTj0nIjEjvmTWekazka6xIt6Uogz5Dm+8=
github.com/knqyf263/go-deb-version v0.0.0-20241115132648-6f4aee6ccd23/go.mod h1:lUaIXCWzf7BRKTY5iEcrYy1TfgbYLYVIS/B2vPkJzOc=
github.com/knqyf263/go-plugin v0.9.0 h1:CQs2+lOPIlkZVtcb835ZYDEoyyWJWLbSTWeCs0EwTwI=
github.com/knqyf263/go-plugin v0.9.0/go.mod h1:2z5lCO1/pez6qGo8CvCxSlBFSEat4MEp1DrnA+f7w8Q=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
Expand Down Expand Up @@ -1466,6 +1469,7 @@ github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgr
github.com/opencontainers/runc v1.3.0/go.mod h1:9wbWt42gV+KRxKRVVugNP6D5+PQciRbenB4fLVsqGPs=
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2 h1:2xZEHOdeQBV6PW8ZtimN863bIOl7OCW/X10K0cnxKeA=
github.com/opencontainers/runtime-tools v0.9.1-0.20251114084447-edf4cb3d2116 h1:tAKu3NkKWZYpqBSOJKwTxT1wIGueiF7gcmcNgr5pNTY=
github.com/opencontainers/runtime-tools v0.9.1-0.20251114084447-edf4cb3d2116/go.mod h1:DKDEfzxvRkoQ6n9TGhxQgg2IM1lY4aM0eaQP4e3oElw=
github.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22F+ISDCJE=
Expand Down Expand Up @@ -1719,6 +1723,7 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cb
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
github.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo=
github.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=
github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA=
github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU=
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
Expand Down
14 changes: 14 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ type Config struct {
SandboxPolicyContainerdSocket string `mapstructure:"sandboxPolicyContainerdSocket"`
SandboxPolicyControlRoot string `mapstructure:"sandboxPolicyControlRoot"`
SandboxPolicyMaxOwners uint64 `mapstructure:"sandboxPolicyMaxOwners"`
EnableSandboxSeccomp bool `mapstructure:"sandboxSeccompEnabled"`
SandboxSeccompNRISocket string `mapstructure:"sandboxSeccompNRISocket"`
EnableRuntimeDetection bool `mapstructure:"runtimeDetectionEnabled"`
EnableSbomFailureReporting bool `mapstructure:"sbomFailureReportingEnabled"`
EnableSbomGeneration bool `mapstructure:"sbomGenerationEnabled"`
Expand Down Expand Up @@ -229,6 +231,8 @@ func LoadConfigOptional(path string, errNotFound bool) (Config, error) {
viper.SetDefault("sandboxPolicyContainerdSocket", "")
viper.SetDefault("sandboxPolicyControlRoot", "")
viper.SetDefault("sandboxPolicyMaxOwners", 4)
viper.SetDefault("sandboxSeccompEnabled", false)
viper.SetDefault("sandboxSeccompNRISocket", "/var/run/nri/nri.sock")
viper.SetDefault("fullPathTracingEnabled", true)
viper.SetDefault("initialDelay", 2*time.Minute)
viper.SetDefault("nodeProfileInterval", 10*time.Minute)
Expand Down Expand Up @@ -364,6 +368,16 @@ func LoadConfigOptional(path string, errNotFound bool) (Config, error) {
}
}

if config.EnableSandboxSeccomp {
if !config.KubernetesMode {
return Config{}, fmt.Errorf("sandboxSeccompEnabled requires kubernetesMode")
}
socket := config.SandboxSeccompNRISocket
if !filepath.IsAbs(socket) || filepath.Clean(socket) != socket {
return Config{}, fmt.Errorf("sandboxSeccompNRISocket must be an absolute canonical path")
}
}

// Validate seccompProfileBackend value
if config.SeccompProfileBackend != "" &&
config.SeccompProfileBackend != SeccompBackendStorage &&
Expand Down
1 change: 1 addition & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func TestLoadConfig(t *testing.T) {
NetworkStreamingInterval: 2 * time.Minute,
InitialDelay: 2 * time.Minute,
SandboxPolicyMaxOwners: 4,
SandboxSeccompNRISocket: "/var/run/nri/nri.sock",
HostSBOMRescanInterval: 24 * time.Hour,
HostSbomOffloadEnabled: true,
MaxSniffingTime: 24 * time.Hour,
Expand Down
Loading
Loading