Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split repo trusted setting #4025

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f7516da
Split repo trusted setting
qwerty287 Aug 11, 2024
9de4565
Merge branch 'main' into trusted-split
qwerty287 Aug 16, 2024
2f05a97
Merge branch 'main' into trusted-split
qwerty287 Aug 18, 2024
2e6bbc8
Merge branch 'main' into trusted-split
qwerty287 Aug 27, 2024
7f0a241
Merge branch 'main' into trusted-split
qwerty287 Aug 29, 2024
9abe0d1
add migration note
qwerty287 Aug 29, 2024
1efcfe0
Merge branch 'main' into trusted-split
qwerty287 Aug 29, 2024
59b4ddf
Merge branch 'main' into trusted-split
6543 Sep 5, 2024
6b2cbea
update docs
6543 Sep 5, 2024
6d3c769
Merge branch 'main' into trusted-split
qwerty287 Sep 7, 2024
c608830
force col update
qwerty287 Sep 7, 2024
b07645b
fix lint and strings
qwerty287 Sep 7, 2024
6b5da61
fix tests
qwerty287 Sep 7, 2024
c3edc07
Merge branch 'main' into trusted-split
qwerty287 Sep 7, 2024
32313e1
Merge branch 'main' into trusted-split
qwerty287 Sep 11, 2024
2fe31d8
Merge branch 'main' into trusted-split
qwerty287 Sep 14, 2024
8b8eee1
fix
qwerty287 Sep 14, 2024
8723f03
Merge branch 'main' into trusted-split
qwerty287 Sep 15, 2024
ac4aee9
Merge branch 'main' into trusted-split
qwerty287 Sep 20, 2024
63c9747
review
qwerty287 Sep 20, 2024
c7a4d98
update cli exec metadata
qwerty287 Sep 20, 2024
eb501e9
format
qwerty287 Sep 21, 2024
9f035c5
Merge branch 'main' into trusted-split
qwerty287 Sep 21, 2024
509280b
Merge branch 'main' into trusted-split
qwerty287 Sep 24, 2024
6346adb
Merge branch 'main' into trusted-split
qwerty287 Sep 25, 2024
01fb044
Merge branch 'main' into trusted-split
qwerty287 Sep 27, 2024
7204bd1
remove resources
qwerty287 Sep 27, 2024
49b4f2b
fix
qwerty287 Sep 27, 2024
a47ed94
Update pipeline/frontend/yaml/linter/linter_test.go
6543 Sep 30, 2024
3071a5a
Apply suggestions from code review
6543 Sep 30, 2024
8143772
Merge branch 'main' into trusted-split
6543 Sep 30, 2024
53f1fa2
Merge branch 'main' into trusted-split
qwerty287 Sep 30, 2024
06f3432
Merge branch 'main' into trusted-split
qwerty287 Oct 6, 2024
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
7 changes: 6 additions & 1 deletion cli/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,12 @@ func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, ax

// lint the yaml file
err = linter.New(
linter.WithTrusted(true),
linter.WithTrusted(linter.TrustedConfiguration{
Network: true,
Volumes: true,
Resources: true,
Security: true,
}),
linter.PrivilegedPlugins(privilegedPlugins),
linter.WithTrustedClonePlugins(constant.TrustedClonePlugins),
).Lint([]*linter.WorkflowConfig{{
Expand Down
7 changes: 6 additions & 1 deletion cli/exec/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ func metadataFromContext(_ context.Context, c *cli.Command, axis matrix.Axis) me
CloneURL: c.String("repo-clone-url"),
CloneSSHURL: c.String("repo-clone-ssh-url"),
Private: c.Bool("repo-private"),
Trusted: c.Bool("repo-trusted"),
Trusted: metadata.TrustedConfiguration{
Security: c.Bool("repo-trusted"),
Network: c.Bool("repo-trusted"),
Resources: c.Bool("repo-trusted"),
Volumes: c.Bool("repo-trusted"),
},
},
Curr: metadata.Pipeline{
Number: c.Int("pipeline-number"),
Expand Down
7 changes: 6 additions & 1 deletion cli/lint/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,12 @@ func lintFile(_ context.Context, c *cli.Command, file string) error {

// TODO: lint multiple files at once to allow checks for sth like "depends_on" to work
err = linter.New(
linter.WithTrusted(true),
linter.WithTrusted(linter.TrustedConfiguration{
Network: true,
Volumes: true,
Resources: true,
Security: true,
}),
linter.PrivilegedPlugins(c.StringSlice("plugins-privileged")),
linter.WithTrustedClonePlugins(c.StringSlice("plugins-trusted-clone")),
).Lint([]*linter.WorkflowConfig{config})
Expand Down
38 changes: 36 additions & 2 deletions cmd/server/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4859,7 +4859,7 @@ const docTemplate = `{
"type": "integer"
},
"trusted": {
"type": "boolean"
"$ref": "#/definitions/model.TrustedConfiguration"
},
"visibility": {
"$ref": "#/definitions/RepoVisibility"
Expand Down Expand Up @@ -4894,7 +4894,7 @@ const docTemplate = `{
"type": "integer"
},
"trusted": {
"type": "boolean"
"$ref": "#/definitions/model.TrustedConfigurationPatch"
},
"visibility": {
"type": "string"
Expand Down Expand Up @@ -5169,6 +5169,40 @@ const docTemplate = `{
"ForgeTypeAddon"
]
},
"model.TrustedConfiguration": {
"type": "object",
"properties": {
"network": {
"type": "boolean"
},
"resources": {
"type": "boolean"
},
"security": {
"type": "boolean"
},
"volumes": {
"type": "boolean"
}
}
},
"model.TrustedConfigurationPatch": {
"type": "object",
"properties": {
"network": {
"type": "boolean"
},
"resources": {
"type": "boolean"
},
"security": {
"type": "boolean"
},
"volumes": {
"type": "boolean"
}
}
},
"model.Workflow": {
"type": "object",
"properties": {
Expand Down
5 changes: 4 additions & 1 deletion docs/docs/20-usage/50-environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ This is the reference list of all environment variables available to your pipeli
| `CI_REPO_CLONE_SSH_URL` | repository SSH clone URL | `[email protected]:john-doe/my-repo.git` |
| `CI_REPO_DEFAULT_BRANCH` | repository default branch | `main` |
| `CI_REPO_PRIVATE` | repository is private | `true` |
| `CI_REPO_TRUSTED` | repository is trusted | `false` |
| `CI_REPO_TRUSTED_NETWORK` | repository has trusted network access | `false` |
| `CI_REPO_TRUSTED_RESOURCES` | repository has trusted resources access | `false` |
| `CI_REPO_TRUSTED_VOLUMES` | repository has trusted volumes access | `false` |
| `CI_REPO_TRUSTED_SECURITY` | repository has trusted security access | `false` |
| | **Current Commit** | |
| `CI_COMMIT_SHA` | commit SHA | `eba09b46064473a1d345da7abf28b477468e8dbd` |
| `CI_COMMIT_REF` | commit ref | `refs/heads/main` |
Expand Down
1 change: 1 addition & 0 deletions docs/docs/91-migrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Some versions need some changes to the server configuration or the pipeline conf
- Removed `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST`
- Migrated to rfc9421 for webhook signatures
- Renamed `start_time`, `end_time`, `created_at`, `started_at`, `finished_at` and `reviewed_at` JSON fields to `started`, `finished`, `created`, `started`, `finished`, `reviewed`
- JSON field `trusted` on repo model was changed from boolean to object
- Update all webhooks by pressing the "Repair all" button in the admin settings as the webhook token claims have changed
- Crons now use standard Linux syntax without seconds
- Replaced `configs` object by `netrc` in external configuration APIs
Expand Down
4 changes: 4 additions & 0 deletions pipeline/frontend/metadata/drone_compatibility_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ CI_REPO_PRIVATE=false
CI_REPO_REMOTE_ID=4
CI_REPO_SCM=git
CI_REPO_TRUSTED=false
CI_REPO_TRUSTED_NETWORK=false
CI_REPO_TRUSTED_RESOURCES=false
CI_REPO_TRUSTED_VOLUMES=false
CI_REPO_TRUSTED_SECURITY=false
CI_REPO_URL=http://1.2.3.4:3000/test/woodpecker-test
CI_STEP_NAME=
CI_STEP_NUMBER=0
Expand Down
29 changes: 17 additions & 12 deletions pipeline/frontend/metadata/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,23 @@ func (m *Metadata) Environ() map[string]string {
prevSourceBranch, prevTargetBranch := getSourceTargetBranches(m.Prev.Commit.Refspec)

params := map[string]string{
"CI": m.Sys.Name,
"CI_REPO": path.Join(m.Repo.Owner, m.Repo.Name),
"CI_REPO_NAME": m.Repo.Name,
"CI_REPO_OWNER": m.Repo.Owner,
"CI_REPO_REMOTE_ID": m.Repo.RemoteID,
"CI_REPO_SCM": "git",
"CI_REPO_URL": m.Repo.ForgeURL,
"CI_REPO_CLONE_URL": m.Repo.CloneURL,
"CI_REPO_CLONE_SSH_URL": m.Repo.CloneSSHURL,
"CI_REPO_DEFAULT_BRANCH": m.Repo.Branch,
"CI_REPO_PRIVATE": strconv.FormatBool(m.Repo.Private),
"CI_REPO_TRUSTED": strconv.FormatBool(m.Repo.Trusted),
"CI": m.Sys.Name,
"CI_REPO": path.Join(m.Repo.Owner, m.Repo.Name),
"CI_REPO_NAME": m.Repo.Name,
"CI_REPO_OWNER": m.Repo.Owner,
"CI_REPO_REMOTE_ID": m.Repo.RemoteID,
"CI_REPO_SCM": "git",
"CI_REPO_URL": m.Repo.ForgeURL,
"CI_REPO_CLONE_URL": m.Repo.CloneURL,
"CI_REPO_CLONE_SSH_URL": m.Repo.CloneSSHURL,
"CI_REPO_DEFAULT_BRANCH": m.Repo.Branch,
"CI_REPO_PRIVATE": strconv.FormatBool(m.Repo.Private),
"CI_REPO_TRUSTED_NETWORK": strconv.FormatBool(m.Repo.Trusted.Network),
"CI_REPO_TRUSTED_RESOURCES": strconv.FormatBool(m.Repo.Trusted.Resources),
"CI_REPO_TRUSTED_VOLUMES": strconv.FormatBool(m.Repo.Trusted.Volumes),
"CI_REPO_TRUSTED_SECURITY": strconv.FormatBool(m.Repo.Trusted.Security),
// Deprecated remove in 4.x
"CI_REPO_TRUSTED": strconv.FormatBool(m.Repo.Trusted.Security && m.Repo.Trusted.Network && m.Repo.Trusted.Resources && m.Repo.Trusted.Volumes),

"CI_COMMIT_SHA": m.Curr.Commit.Sha,
"CI_COMMIT_REF": m.Curr.Commit.Ref,
Expand Down
29 changes: 18 additions & 11 deletions pipeline/frontend/metadata/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ type (

// Repo defines runtime metadata for a repository.
Repo struct {
ID int64 `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Owner string `json:"owner,omitempty"`
RemoteID string `json:"remote_id,omitempty"`
ForgeURL string `json:"forge_url,omitempty"`
CloneURL string `json:"clone_url,omitempty"`
CloneSSHURL string `json:"clone_url_ssh,omitempty"`
Private bool `json:"private,omitempty"`
Secrets []Secret `json:"secrets,omitempty"`
Branch string `json:"default_branch,omitempty"`
Trusted bool `json:"trusted,omitempty"`
ID int64 `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Owner string `json:"owner,omitempty"`
RemoteID string `json:"remote_id,omitempty"`
ForgeURL string `json:"forge_url,omitempty"`
CloneURL string `json:"clone_url,omitempty"`
CloneSSHURL string `json:"clone_url_ssh,omitempty"`
Private bool `json:"private,omitempty"`
Secrets []Secret `json:"secrets,omitempty"`
Branch string `json:"default_branch,omitempty"`
Trusted TrustedConfiguration `json:"trusted_conf,omitempty"`
}

// Pipeline defines runtime metadata for a pipeline.
Expand Down Expand Up @@ -121,4 +121,11 @@ type (
// URL returns the root url of a configured forge
URL() string
}

TrustedConfiguration struct {
Network bool `json:"network,omitempty"`
Volumes bool `json:"volumes,omitempty"`
Resources bool `json:"resources,omitempty"`
Security bool `json:"security,omitempty"`
}
)
38 changes: 19 additions & 19 deletions pipeline/frontend/yaml/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,23 +92,23 @@ type ResourceLimit struct {

// Compiler compiles the yaml.
type Compiler struct {
local bool
escalated []string
prefix string
volumes []string
networks []string
env map[string]string
cloneEnv map[string]string
workspaceBase string
workspacePath string
metadata metadata.Metadata
registries []Registry
secrets map[string]Secret
reslimit ResourceLimit
defaultClonePlugin string
trustedClonePlugins []string
trustedPipeline bool
netrcOnlyTrusted bool
local bool
escalated []string
prefix string
volumes []string
networks []string
env map[string]string
cloneEnv map[string]string
workspaceBase string
workspacePath string
metadata metadata.Metadata
registries []Registry
secrets map[string]Secret
reslimit ResourceLimit
defaultClonePlugin string
trustedClonePlugins []string
securityTrustedPipeline bool
netrcOnlyTrusted bool
}

// New creates a new Compiler with options.
Expand Down Expand Up @@ -206,7 +206,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er
}

// only inject netrc if it's a trusted repo or a trusted plugin
if !c.netrcOnlyTrusted || c.trustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage(c.trustedClonePlugins)) {
if !c.netrcOnlyTrusted || c.securityTrustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage(c.trustedClonePlugins)) {
for k, v := range c.cloneEnv {
step.Environment[k] = v
}
Expand Down Expand Up @@ -263,7 +263,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er
}

// inject netrc if it's a trusted repo or a trusted clone-plugin
if c.trustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage(c.trustedClonePlugins)) {
if c.securityTrustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage(c.trustedClonePlugins)) {
for k, v := range c.cloneEnv {
step.Environment[k] = v
}
Expand Down
6 changes: 3 additions & 3 deletions pipeline/frontend/yaml/compiler/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ func WithTrustedClonePlugins(images []string) Option {
}
}

// WithTrusted configures the compiler with the trusted repo option.
func WithTrusted(trusted bool) Option {
// WithTrustedSecurity configures the compiler with the trusted repo option.
func WithTrustedSecurity(trusted bool) Option {
return func(compiler *Compiler) {
compiler.trustedPipeline = trusted
compiler.securityTrustedPipeline = trusted
}
}

Expand Down
69 changes: 41 additions & 28 deletions pipeline/frontend/yaml/linter/linter.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,18 @@ import (

// A Linter lints a pipeline configuration.
type Linter struct {
trusted bool
trusted TrustedConfiguration
privilegedPlugins *[]string
trustedClonePlugins *[]string
}

type TrustedConfiguration struct {
Network bool
Volumes bool
Resources bool
Security bool
}

// New creates a new Linter with options.
func New(opts ...Option) *Linter {
linter := new(Linter)
Expand Down Expand Up @@ -143,10 +150,8 @@ func (l *Linter) lintContainers(config *WorkflowConfig, area string) error {
if err := l.lintImage(config, container, area); err != nil {
linterErr = multierr.Append(linterErr, err)
}
if !l.trusted {
if err := l.lintTrusted(config, container, area); err != nil {
linterErr = multierr.Append(linterErr, err)
}
if err := l.lintTrusted(config, container, area); err != nil {
linterErr = multierr.Append(linterErr, err)
}
if err := l.lintSettings(config, container, area); err != nil {
linterErr = multierr.Append(linterErr, err)
Expand Down Expand Up @@ -204,32 +209,40 @@ func (l *Linter) lintSettings(config *WorkflowConfig, c *types.Container, field
func (l *Linter) lintTrusted(config *WorkflowConfig, c *types.Container, area string) error {
yamlPath := fmt.Sprintf("%s.%s", area, c.Name)
errors := []string{}
if c.Privileged {
errors = append(errors, "Insufficient privileges to use privileged mode")
}
if c.ShmSize != 0 {
errors = append(errors, "Insufficient privileges to override shm_size")
}
if len(c.DNS) != 0 {
errors = append(errors, "Insufficient privileges to use custom dns")
}
if len(c.DNSSearch) != 0 {
errors = append(errors, "Insufficient privileges to use dns_search")
}
if len(c.Devices) != 0 {
errors = append(errors, "Insufficient privileges to use devices")
}
if len(c.ExtraHosts) != 0 {
errors = append(errors, "Insufficient privileges to use extra_hosts")
if !l.trusted.Security {
if c.Privileged {
errors = append(errors, "Insufficient privileges to use privileged mode")
}
}
if len(c.NetworkMode) != 0 {
errors = append(errors, "Insufficient privileges to use network_mode")
if !l.trusted.Resources {
if c.ShmSize != 0 {
errors = append(errors, "Insufficient privileges to override shm_size")
}
}
if len(c.Volumes.Volumes) != 0 {
errors = append(errors, "Insufficient privileges to use volumes")
if !l.trusted.Network {
if len(c.DNS) != 0 {
errors = append(errors, "Insufficient privileges to use custom dns")
}
if len(c.DNSSearch) != 0 {
errors = append(errors, "Insufficient privileges to use dns_search")
}
if len(c.ExtraHosts) != 0 {
errors = append(errors, "Insufficient privileges to use extra_hosts")
}
if len(c.NetworkMode) != 0 {
errors = append(errors, "Insufficient privileges to use network_mode")
}
}
if len(c.Tmpfs) != 0 {
errors = append(errors, "Insufficient privileges to use tmpfs")
if !l.trusted.Volumes {
if len(c.Devices) != 0 {
errors = append(errors, "Insufficient privileges to use devices")
}
if len(c.Volumes.Volumes) != 0 {
errors = append(errors, "Insufficient privileges to use volumes")
}
if len(c.Tmpfs) != 0 {
errors = append(errors, "Insufficient privileges to use tmpfs")
}
}

if len(errors) > 0 {
Expand Down
7 changes: 6 additions & 1 deletion pipeline/frontend/yaml/linter/linter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ steps:
conf, err := yaml.ParseString(testd.Data)
assert.NoError(t, err)

assert.NoError(t, linter.New(linter.WithTrusted(true)).Lint([]*linter.WorkflowConfig{{
assert.NoError(t, linter.New(linter.WithTrusted(linter.TrustedConfiguration{
Network: true,
Volumes: true,
Resources: true,
Security: true,
})).Lint([]*linter.WorkflowConfig{{
File: testd.Title,
RawConfig: testd.Data,
Workflow: conf,
Expand Down
Loading