当前位置:网站首页>Trivy [3] custom scanning strategy
Trivy [3] custom scanning strategy
2022-07-28 23:32:00 【ghostwritten】
List of articles
1. brief introduction
You can go to Rego Writing custom policies in . After writing the custom policy , You can pass the directory where these policies are stored through options –policy.
trivy conf --policy /path/to/custom_policies --namespaces user /path/to/config_dir
2. File format
If the file name matches the following file pattern ,Trivy This file will be parsed and passed to you as input Rego Strategy .
| File format | File mode |
|---|---|
| JSON | *.json |
| YAML | .yaml and .yml |
| Dockerfile | Dockerfile, Dockerfile., and .Dockerfile |
| Containerfile | Containerfile, Containerfile., and .Containerfile |
| Terraform | .tf and .tf.json |
3. Configuration language
In the above general file format ,Trivy The following types of configuration files will be automatically recognized :
CloudFormation(JSON/YAML)Kubernetes(JSON/YAML)Helm(YAML)Terraform Plan(JSON)
4. Rego Format
A package must contain only one policy .
package user.kubernetes.ID001
import lib.result
__rego_metadata__ := {
"id": "ID001",
"title": "Deployment not allowed",
"severity": "LOW",
"description": "Deployments are not allowed because of some reasons.",
}
__rego_input__ := {
"selector": [
{
"type": "kubernetes"},
],
}
deny[res] {
input.kind == "Deployment"
msg := sprintf("Found deployment '%s' but deployments are not allowed", [input.metadata.name])
res := result.new(msg, input)
}
In this example ,ID001“ Deployment is not allowed ” stay define user.kubernetes.ID001. If you add a new custom policy , You must define it under the new package , for example user.kubernetes.ID002.
5. rego structure
package( Essential )- Must follow Rego The specification of
- Every policy must be unique
- Should include a unique strategy ID
- You can include the group name , for example kubernetes For the sake of clarity
- The group name has no effect on policy evaluation
import data.lib.result( Optional )
If you want to decorate your results with line numbers and code highlighting , Can define__rego_metadata__( Optional )
For the sake of clarity , These values should be defined , Because these values will be displayed in the scan results__rego_input__( Optional )
When you want to specify the input format, you can definedeny( Essential )
Should be deny Or start from deny_
Even thoughwarn,warn_*,violation,violation_It also applies to compatibility , but deny It is recommended to use severity , Because it can__rego_metadata__.
One of the following should be returned :
The result of the callresult.new(msg, cause).msgyes string Describe the occurrence of the problem ,causeIs the attribute of the problem / object . Providing this allows Trivy Determine the line number and highlight the code in the output .
A string Indicates the detected problem
althoughobjectwithmsgField is accepted , But other fields are discarded ,string Ifresult.new()Don't use , It is recommended to use .
for example{"msg": "deny message", "details": "something"}
5.1 Package
user.kubernetes.ID001
By default , It's just builtin.* Evaluation package . If you define a custom package , Must pass --namespaces Option specifies the package prefix .
trivy conf --policy /path/to/custom_policies --namespaces user /path/to/config_dir
under these circumstances ,user.* Will be evaluated . Allow any package prefix , for example main and user
5.2 Metadata
Metadata helps enrich with useful information Trivy The results of the scan .
__rego_metadata__ := {
"id": "ID001",
"title": "Deployment not allowed",
"severity": "LOW",
"description": "Deployments are not allowed because of some reasons.",
"recommended_actions": "Remove Deployment",
"url": "https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits",
}
All fields below __rego_metadata__ It's all optional .
| Field name | permitted | The default value is | In the table | stay JSON in |
|---|---|---|---|---|
| id | Any character | Do not apply | yes | yes |
| title | Any character | Do not apply | yes | yes |
| severity | LOW, MEDIUM, HIGH,CRITICAL | Unknown | yes | yes |
| description | Any character | no | yes | |
| recommended_actions | Any character | no | yes | |
| url | Any character | no | yes |
Some fields will be displayed in the scan results .
k.yaml (kubernetes)
───────────────────
Tests: 32 (SUCCESSES: 31, FAILURES: 1, EXCEPTIONS: 0)
Failures: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
LOW: Found deployment 'my-deployment' but deployments are not allowed
════════════════════════════════════════════════════════════════════════
Deployments are not allowed because of some reasons.
────────────────────────────────────────────────────────────────────────
k.yaml:1-2
────────────────────────────────────────────────────────────────────────
1 ┌ apiVersion: v1
2 └ kind: Deployment
────────────────────────────────────────────────────────────────────────
5.3 Input
You can Specify the input format __rego_input__. All fields below __rego_input It's all optional .
__rego_input__ := {
"combine": false,
"selector": [
{
"type": "kubernetes"},
],
}
combine(boolean) Set to true when , All configuration files in the specified directory are merged into one input data structure .selector(array) This option filters input by file format or configuration language . In the example above ,Trivy Only will Kubernetes
File transfer Give this policy . Even if Dockerfile, It will not be passed to the policy as input . When Kubernetes
When the configuration language is not recognized , Will use JSON And other file formats as type. When a configuration language is recognized , It will cover type.typeAccept kubernetes, dockerfile, cloudformation, terraform,terraformplan, json, or yaml.
stay “combine” In mode ,input The document becomes an array , Each of these elements is an object with two fields :
- “
path”: “path/to/file”: The relative file path of the corresponding file - “
contents”: …: The parsing content of the corresponding file
Now? , You can ensure that duplicate values match throughout the configuration file .
5.4 Return value
stay “combine” In mode ,deny The entry point must return an object with two keys
filepath( Essential ): The relative file path of the file being evaluatedmsg( Essential ): A message describing the problem
deny[res] {
resource := input[i].contents
... some logic ...
res := {
"filepath": input[i].path,
"msg": "something bad",
}
}
6. Customize data
Custom policies may require additional data to determine the answer .
for example , List of resources allowed to be created .Trivy Allow the path to be passed to with --data Flag data file , Instead of hard coding this information in the policy .
Given the following yaml file
$ cd examples/misconf/custom-data
$ cat data/ports.yaml [~/src/github.com/aquasecurity/trivy/examples/misconf/custom-data]
services:
ports:
- "20"
- "20/tcp"
- "20/udp"
- "23"
- "23/tcp"
This can import your strategy :
import data.services
ports := services.ports
then , You need to go through --data Option pass data path .Trivy Recursively searching JSON ( *.json) and YAML ( *.yaml) The specified path of the file .
$ trivy conf --policy ./policy --data data --namespaces user ./configs
6. rego test
To help you verify the correctness of the custom policy ,OPA Provides you with a framework , You can use this framework to write tests for your strategy . By writing tests for your custom policies , You can speed up the development of new rules , And reduce the time required to modify rules as requirements develop .
For more details , see also Strategy test .
Trivy The core of the library Fanal It can be used as Go Library import . You can scan Go And use Go The test method of ( For example, table driven testing ) Test your custom policy . This allows you to use the actual configuration file as input , This makes it easy to prepare test data and ensure that your custom strategy is effective in practice .
especially Dockerfile and HCL It needs to be converted into structured data as input , This may be different from the expected input format .
We suggest that OPA and Go test , Because they have different roles , Such as unit testing and integration testing .
The following example stores the allowed and denied configuration files in the directory . Successes Include successful results , also Failures Include the result of failure .
{
name: "disallowed ports",
input: "configs/",
fields: fields{
policyPaths: []string{
"policy"},
dataPaths: []string{
"data"},
namespaces: []string{
"user"},
},
want: []types.Misconfiguration{
{
FileType: types.Dockerfile,
FilePath: "Dockerfile.allowed",
Successes: types.MisconfResults{
{
Namespace: "user.dockerfile.ID002",
PolicyMetadata: types.PolicyMetadata{
ID: "ID002",
Type: "Docker Custom Check",
Title: "Disallowed ports exposed",
Severity: "HIGH",
},
},
},
},
{
FileType: types.Dockerfile,
FilePath: "Dockerfile.denied",
Failures: types.MisconfResults{
{
Namespace: "user.dockerfile.ID002",
Message: "Port 23 should not be exposed",
PolicyMetadata: types.PolicyMetadata{
ID: "ID002",
Type: "Docker Custom Check",
Title: "Disallowed ports exposed",
Severity: "HIGH",
},
},
},
},
},
},
Dockerfile.allowed There is a successful result Successes, and Dockerfile.denied There is a result of failure Failures.
7. debug Strategy
When dealing with more complex queries ( Or learning Rego when ), It is useful to know exactly how the strategy is applied . So , You can use the –trace sign . This will come from Open Policy Agent Output a large trace , Only failed strategies will show traces . If you want to debug the passed policy , You need to deliberately fail . As shown below :
$ trivy conf --trace configs/
2022-05-16T13:47:58.853+0100 INFO Detected config files: 1
Dockerfile (dockerfile)
=======================
Tests: 23 (SUCCESSES: 21, FAILURES: 2, EXCEPTIONS: 0)
Failures: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)
MEDIUM: Specify a tag in the 'FROM' statement for image 'alpine'
═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
When using a 'FROM' statement you should use a specific tag to avoid uncontrolled behavior when the image is updated.
See https://avd.aquasec.com/misconfig/ds001
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Dockerfile:1
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 [ FROM alpine:latest
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
HIGH: Last USER command in Dockerfile should not be 'root'
═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile.
See https://avd.aquasec.com/misconfig/ds002
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Dockerfile:3
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
3 [ USER root
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
ID: DS001
File: Dockerfile
Namespace: builtin.dockerfile.DS001
Query: data.builtin.dockerfile.DS001.deny
Message: Specify a tag in the 'FROM' statement for image 'alpine'
TRACE Enter data.builtin.dockerfile.DS001.deny = _
TRACE | Eval data.builtin.dockerfile.DS001.deny = _
TRACE | Index data.builtin.dockerfile.DS001.deny (matched 1 rule)
TRACE | Enter data.builtin.dockerfile.DS001.deny
TRACE | | Eval output = data.builtin.dockerfile.DS001.fail_latest[_]
TRACE | | Index data.builtin.dockerfile.DS001.fail_latest (matched 1 rule)
TRACE | | Enter data.builtin.dockerfile.DS001.fail_latest
TRACE | | | Eval output = data.builtin.dockerfile.DS001.image_tags[_]
TRACE | | | Index data.builtin.dockerfile.DS001.image_tags (matched 2 rules)
TRACE | | | Enter data.builtin.dockerfile.DS001.image_tags
TRACE | | | | Eval from = data.lib.docker.from[_]
TRACE | | | | Index data.lib.docker.from (matched 1 rule)
TRACE | | | | Enter data.lib.docker.from
TRACE | | | | | Eval instruction = input.stages[_][_]
TRACE | | | | | Eval instruction.Cmd = "from"
TRACE | | | | | Exit data.lib.docker.from
TRACE | | | | Redo data.lib.docker.from
TRACE | | | | | Redo instruction.Cmd = "from"
TRACE | | | | | Redo instruction = input.stages[_][_]
TRACE | | | | | Eval instruction.Cmd = "from"
TRACE | | | | | Fail instruction.Cmd = "from"
TRACE | | | | | Redo instruction = input.stages[_][_]
TRACE | | | | | Eval instruction.Cmd = "from"
TRACE | | | | | Fail instruction.Cmd = "from"
TRACE | | | | | Redo instruction = input.stages[_][_]
TRACE | | | | Eval name = from.Value[0]
TRACE | | | | Eval not startswith(name, "$")
TRACE | | | | Enter startswith(name, "$")
TRACE | | | | | Eval startswith(name, "$")
TRACE | | | | | Fail startswith(name, "$")
TRACE | | | | Eval data.builtin.dockerfile.DS001.parse_tag(name, __local505__)
TRACE | | | | Index data.builtin.dockerfile.DS001.parse_tag (matched 2 rules)
TRACE | | | | Enter data.builtin.dockerfile.DS001.parse_tag
TRACE | | | | | Eval split(name, ":", __local504__)
TRACE | | | | | Eval [img, tag] = __local504__
TRACE | | | | | Exit data.builtin.dockerfile.DS001.parse_tag
TRACE | | | | Eval [img, tag] = __local505__
TRACE | | | | Eval output = {
"cmd": from, "img": img, "tag": tag}
TRACE | | | | Exit data.builtin.dockerfile.DS001.image_tags
TRACE | | | Redo data.builtin.dockerfile.DS001.image_tags
TRACE | | | | Redo output = {
"cmd": from, "img": img, "tag": tag}
TRACE | | | | Redo [img, tag] = __local505__
TRACE | | | | Redo data.builtin.dockerfile.DS001.parse_tag(name, __local505__)
TRACE | | | | Redo data.builtin.dockerfile.DS001.parse_tag
TRACE | | | | | Redo [img, tag] = __local504__
TRACE | | | | | Redo split(name, ":", __local504__)
TRACE | | | | Enter data.builtin.dockerfile.DS001.parse_tag
TRACE | | | | | Eval tag = "latest"
TRACE | | | | | Eval not contains(img, ":")
TRACE | | | | | Enter contains(img, ":")
TRACE | | | | | | Eval contains(img, ":")
TRACE | | | | | | Exit contains(img, ":")
TRACE | | | | | Redo contains(img, ":")
TRACE | | | | | | Redo contains(img, ":")
TRACE | | | | | Fail not contains(img, ":")
TRACE | | | | | Redo tag = "latest"
TRACE | | | | Redo name = from.Value[0]
TRACE | | | | Redo from = data.lib.docker.from[_]
TRACE | | | Enter data.builtin.dockerfile.DS001.image_tags
TRACE | | | | Eval from = data.lib.docker.from[i]
TRACE | | | | Index data.lib.docker.from (matched 1 rule)
TRACE | | | | Eval name = from.Value[0]
TRACE | | | | Eval cmd_obj = input.stages[j][k]
TRACE | | | | Eval possibilities = {
"arg", "env"}
TRACE | | | | Eval cmd_obj.Cmd = possibilities[l]
TRACE | | | | Fail cmd_obj.Cmd = possibilities[l]
TRACE | | | | Redo possibilities = {
"arg", "env"}
TRACE | | | | Redo cmd_obj = input.stages[j][k]
TRACE | | | | Eval possibilities = {
"arg", "env"}
TRACE | | | | Eval cmd_obj.Cmd = possibilities[l]
TRACE | | | | Fail cmd_obj.Cmd = possibilities[l]
TRACE | | | | Redo possibilities = {
"arg", "env"}
TRACE | | | | Redo cmd_obj = input.stages[j][k]
TRACE | | | | Eval possibilities = {
"arg", "env"}
TRACE | | | | Eval cmd_obj.Cmd = possibilities[l]
TRACE | | | | Fail cmd_obj.Cmd = possibilities[l]
TRACE | | | | Redo possibilities = {
"arg", "env"}
TRACE | | | | Redo cmd_obj = input.stages[j][k]
TRACE | | | | Redo name = from.Value[0]
TRACE | | | | Redo from = data.lib.docker.from[i]
TRACE | | | Eval __local752__ = output.img
TRACE | | | Eval neq(__local752__, "scratch")
TRACE | | | Eval __local753__ = output.img
TRACE | | | Eval not data.builtin.dockerfile.DS001.is_alias(__local753__)
TRACE | | | Enter data.builtin.dockerfile.DS001.is_alias(__local753__)
TRACE | | | | Eval data.builtin.dockerfile.DS001.is_alias(__local753__)
TRACE | | | | Index data.builtin.dockerfile.DS001.is_alias (matched 1 rule, early exit)
TRACE | | | | Enter data.builtin.dockerfile.DS001.is_alias
TRACE | | | | | Eval img = data.builtin.dockerfile.DS001.get_aliases[_]
TRACE | | | | | Index data.builtin.dockerfile.DS001.get_aliases (matched 1 rule)
TRACE | | | | | Enter data.builtin.dockerfile.DS001.get_aliases
TRACE | | | | | | Eval from_cmd = data.lib.docker.from[_]
TRACE | | | | | | Index data.lib.docker.from (matched 1 rule)
TRACE | | | | | | Eval __local749__ = from_cmd.Value
TRACE | | | | | | Eval data.builtin.dockerfile.DS001.get_alias(__local749__, __local503__)
TRACE | | | | | | Index data.builtin.dockerfile.DS001.get_alias (matched 1 rule)
TRACE | | | | | | Enter data.builtin.dockerfile.DS001.get_alias
TRACE | | | | | | | Eval __local748__ = values[i]
TRACE | | | | | | | Eval lower(__local748__, __local501__)
TRACE | | | | | | | Eval "as" = __local501__
TRACE | | | | | | | Fail "as" = __local501__
TRACE | | | | | | | Redo lower(__local748__, __local501__)
TRACE | | | | | | | Redo __local748__ = values[i]
TRACE | | | | | | Fail data.builtin.dockerfile.DS001.get_alias(__local749__, __local503__)
TRACE | | | | | | Redo __local749__ = from_cmd.Value
TRACE | | | | | | Redo from_cmd = data.lib.docker.from[_]
TRACE | | | | | Fail img = data.builtin.dockerfile.DS001.get_aliases[_]
TRACE | | | | Fail data.builtin.dockerfile.DS001.is_alias(__local753__)
TRACE | | | Eval output.tag = "latest"
TRACE | | | Exit data.builtin.dockerfile.DS001.fail_latest
TRACE | | Redo data.builtin.dockerfile.DS001.fail_latest
TRACE | | | Redo output.tag = "latest"
TRACE | | | Redo __local753__ = output.img
TRACE | | | Redo neq(__local752__, "scratch")
TRACE | | | Redo __local752__ = output.img
TRACE | | | Redo output = data.builtin.dockerfile.DS001.image_tags[_]
TRACE | | Eval __local754__ = output.img
TRACE | | Eval sprintf("Specify a tag in the 'FROM' statement for image '%s'", [__local754__], __local509__)
TRACE | | Eval msg = __local509__
TRACE | | Eval __local755__ = output.cmd
TRACE | | Eval data.lib.docker.result(msg, __local755__, __local510__)
TRACE | | Index data.lib.docker.result (matched 1 rule)
TRACE | | Enter data.lib.docker.result
TRACE | | | Eval object.get(cmd, "EndLine", 0, __local470__)
TRACE | | | Eval object.get(cmd, "Path", "", __local471__)
TRACE | | | Eval object.get(cmd, "StartLine", 0, __local472__)
TRACE | | | Eval result = {
"endline": __local470__, "filepath": __local471__, "msg": msg, "startline": __local472__}
TRACE | | | Exit data.lib.docker.result
TRACE | | Eval res = __local510__
TRACE | | Exit data.builtin.dockerfile.DS001.deny
TRACE | Redo data.builtin.dockerfile.DS001.deny
TRACE | | Redo res = __local510__
TRACE | | Redo data.lib.docker.result(msg, __local755__, __local510__)
TRACE | | Redo data.lib.docker.result
TRACE | | | Redo result = {
"endline": __local470__, "filepath": __local471__, "msg": msg, "startline": __local472__}
TRACE | | | Redo object.get(cmd, "StartLine", 0, __local472__)
TRACE | | | Redo object.get(cmd, "Path", "", __local471__)
TRACE | | | Redo object.get(cmd, "EndLine", 0, __local470__)
TRACE | | Redo __local755__ = output.cmd
TRACE | | Redo msg = __local509__
TRACE | | Redo sprintf("Specify a tag in the 'FROM' statement for image '%s'", [__local754__], __local509__)
TRACE | | Redo __local754__ = output.img
TRACE | | Redo output = data.builtin.dockerfile.DS001.fail_latest[_]
TRACE | Exit data.builtin.dockerfile.DS001.deny = _
TRACE Redo data.builtin.dockerfile.DS001.deny = _
TRACE | Redo data.builtin.dockerfile.DS001.deny = _
TRACE
ID: DS002
File: Dockerfile
Namespace: builtin.dockerfile.DS002
Query: data.builtin.dockerfile.DS002.deny
Message: Last USER command in Dockerfile should not be 'root'
TRACE Enter data.builtin.dockerfile.DS002.deny = _
TRACE | Eval data.builtin.dockerfile.DS002.deny = _
TRACE | Index data.builtin.dockerfile.DS002.deny (matched 2 rules)
TRACE | Enter data.builtin.dockerfile.DS002.deny
TRACE | | Eval data.builtin.dockerfile.DS002.fail_user_count
TRACE | | Index data.builtin.dockerfile.DS002.fail_user_count (matched 1 rule, early exit)
TRACE | | Enter data.builtin.dockerfile.DS002.fail_user_count
TRACE | | | Eval __local771__ = data.builtin.dockerfile.DS002.get_user
TRACE | | | Index data.builtin.dockerfile.DS002.get_user (matched 1 rule)
TRACE | | | Enter data.builtin.dockerfile.DS002.get_user
TRACE | | | | Eval user = data.lib.docker.user[_]
TRACE | | | | Index data.lib.docker.user (matched 1 rule)
TRACE | | | | Enter data.lib.docker.user
TRACE | | | | | Eval instruction = input.stages[_][_]
TRACE | | | | | Eval instruction.Cmd = "user"
TRACE | | | | | Fail instruction.Cmd = "user"
TRACE | | | | | Redo instruction = input.stages[_][_]
TRACE | | | | | Eval instruction.Cmd = "user"
TRACE | | | | | Exit data.lib.docker.user
TRACE | | | | Redo data.lib.docker.user
TRACE | | | | | Redo instruction.Cmd = "user"
TRACE | | | | | Redo instruction = input.stages[_][_]
TRACE | | | | | Eval instruction.Cmd = "user"
TRACE | | | | | Fail instruction.Cmd = "user"
TRACE | | | | | Redo instruction = input.stages[_][_]
TRACE | | | | Eval username = user.Value[_]
TRACE | | | | Exit data.builtin.dockerfile.DS002.get_user
TRACE | | | Redo data.builtin.dockerfile.DS002.get_user
TRACE | | | | Redo username = user.Value[_]
TRACE | | | | Redo user = data.lib.docker.user[_]
TRACE | | | Eval count(__local771__, __local536__)
TRACE | | | Eval lt(__local536__, 1)
TRACE | | | Fail lt(__local536__, 1)
TRACE | | | Redo count(__local771__, __local536__)
TRACE | | | Redo __local771__ = data.builtin.dockerfile.DS002.get_user
TRACE | | Fail data.builtin.dockerfile.DS002.fail_user_count
TRACE | Enter data.builtin.dockerfile.DS002.deny
TRACE | | Eval cmd = data.builtin.dockerfile.DS002.fail_last_user_root[_]
TRACE | | Index data.builtin.dockerfile.DS002.fail_last_user_root (matched 1 rule)
TRACE | | Enter data.builtin.dockerfile.DS002.fail_last_user_root
TRACE | | | Eval stage_users = data.lib.docker.stage_user[_]
TRACE | | | Index data.lib.docker.stage_user (matched 1 rule)
TRACE | | | Enter data.lib.docker.stage_user
TRACE | | | | Eval stage = input.stages[stage_name]
TRACE | | | | Eval users = [cmd | cmd = stage[_]; cmd.Cmd = "user"]
TRACE | | | | Enter cmd = stage[_]; cmd.Cmd = "user"
TRACE | | | | | Eval cmd = stage[_]
TRACE | | | | | Eval cmd.Cmd = "user"
TRACE | | | | | Fail cmd.Cmd = "user"
TRACE | | | | | Redo cmd = stage[_]
TRACE | | | | | Eval cmd.Cmd = "user"
TRACE | | | | | Exit cmd = stage[_]; cmd.Cmd = "user"
TRACE | | | | Redo cmd = stage[_]; cmd.Cmd = "user"
TRACE | | | | | Redo cmd.Cmd = "user"
TRACE | | | | | Redo cmd = stage[_]
TRACE | | | | | Eval cmd.Cmd = "user"
TRACE | | | | | Fail cmd.Cmd = "user"
TRACE | | | | | Redo cmd = stage[_]
TRACE | | | | Exit data.lib.docker.stage_user
TRACE | | | Redo data.lib.docker.stage_user
TRACE | | | | Redo users = [cmd | cmd = stage[_]; cmd.Cmd = "user"]
TRACE | | | | Redo stage = input.stages[stage_name]
TRACE | | | Eval count(stage_users, __local537__)
TRACE | | | Eval len = __local537__
TRACE | | | Eval minus(len, 1, __local538__)
TRACE | | | Eval last = stage_users[__local538__]
TRACE | | | Eval user = last.Value[0]
TRACE | | | Eval user = "root"
TRACE | | | Exit data.builtin.dockerfile.DS002.fail_last_user_root
TRACE | | Redo data.builtin.dockerfile.DS002.fail_last_user_root
TRACE | | | Redo user = "root"
TRACE | | | Redo user = last.Value[0]
TRACE | | | Redo last = stage_users[__local538__]
TRACE | | | Redo minus(len, 1, __local538__)
TRACE | | | Redo len = __local537__
TRACE | | | Redo count(stage_users, __local537__)
TRACE | | | Redo stage_users = data.lib.docker.stage_user[_]
TRACE | | Eval msg = "Last USER command in Dockerfile should not be 'root'"
TRACE | | Eval data.lib.docker.result(msg, cmd, __local540__)
TRACE | | Index data.lib.docker.result (matched 1 rule)
TRACE | | Enter data.lib.docker.result
TRACE | | | Eval object.get(cmd, "EndLine", 0, __local470__)
TRACE | | | Eval object.get(cmd, "Path", "", __local471__)
TRACE | | | Eval object.get(cmd, "StartLine", 0, __local472__)
TRACE | | | Eval result = {
"endline": __local470__, "filepath": __local471__, "msg": msg, "startline": __local472__}
TRACE | | | Exit data.lib.docker.result
TRACE | | Eval res = __local540__
TRACE | | Exit data.builtin.dockerfile.DS002.deny
TRACE | Redo data.builtin.dockerfile.DS002.deny
TRACE | | Redo res = __local540__
TRACE | | Redo data.lib.docker.result(msg, cmd, __local540__)
TRACE | | Redo data.lib.docker.result
TRACE | | | Redo result = {
"endline": __local470__, "filepath": __local471__, "msg": msg, "startline": __local472__}
TRACE | | | Redo object.get(cmd, "StartLine", 0, __local472__)
TRACE | | | Redo object.get(cmd, "Path", "", __local471__)
TRACE | | | Redo object.get(cmd, "EndLine", 0, __local470__)
TRACE | | Redo msg = "Last USER command in Dockerfile should not be 'root'"
TRACE | | Redo cmd = data.builtin.dockerfile.DS002.fail_last_user_root[_]
TRACE | Exit data.builtin.dockerfile.DS002.deny = _
TRACE Redo data.builtin.dockerfile.DS002.deny = _
TRACE | Redo data.builtin.dockerfile.DS002.deny = _
TRACE
Reference resources :
边栏推荐
- Hands on Teaching of servlet use (1)
- Subscript in swift
- 通过Wi-Fi 7实现极高吞吐量——洞察下一代Wi-Fi物理层
- Thesis reading (2) - vggnet of classification
- How to embed AI digital human function in VR panorama? Create a cloud experience
- Advanced C language: pointer (2)
- Runloop principle (II)
- Kotlin function nesting
- trivy【3】自定义扫描策略
- pg_ Installation and use of RMAN "PostgreSQL"
猜你喜欢

参加竞赛同学们的留言 : 第十七届的记忆

当初的“你“为什么做测试/开发程序员?自己存在的价值......

With the "integration of driving and parking", freytek's high-performance domain controller leads the new track

22牛客多校day1 I - Chiitoitsu 概论dp

Applet Download Preview PDF, document cannot open solution

Advanced C language: pointer (2)

一文读懂Okaleido Tiger近期动态,挖掘背后价值与潜力

Development of small programs ②

The Gerrit local code is associated to the remote warehouse

Hands on Teaching of servlet use (1)
随机推荐
Solve the exception that all control files are damaged
22牛客多校day1 I - Chiitoitsu 概论dp
【物理应用】水下浮动风力涡轮机的尾流诱导动态模拟风场附matlab代码
业界首创云原生安全检测双模型!安全狗重磅报告亮相数字中国建设峰会
Runloop principle (II)
WebView optimization
trivy【3】自定义扫描策略
参加竞赛同学们的留言 : 第十七届的记忆
The front mounted ADAS camera in parking increased by 54.15% year-on-year, with TOP10 suppliers taking the lead
RouterOS 有限dns劫持及check
使用这个,你发的消息就无法被监控了
零念科技完成Pre-A轮融资,推动智能驾驶平台软件国产替代
MyCms 自媒体商城 v3.6 发布,兼容微擎应用开发(Laravel框架)
多模态模型小抄(1)
字节8年女测试总监工作感悟—写给想转行或即将进入测试行业的女生们...
The functions and differences of display, visibility and overflow
Thesis reading (3) - googlenet of classification
Recurrent neural network (RNN)
【图像分割】基于方向谷形检测实现静脉纹路分割附MATLAB代码
IOS interview
