Split repo trusted setting (#4025)

This commit is contained in:
qwerty287
2024-11-01 22:37:31 +02:00
committed by GitHub
parent 383bfbb6de
commit 29474fc7d9
26 changed files with 373 additions and 193 deletions

View File

@@ -166,6 +166,9 @@ 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_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

View File

@@ -51,18 +51,22 @@ 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": m.Repo.SCM,
"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": m.Repo.SCM,
"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_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.Volumes),
"CI_COMMIT_SHA": m.Curr.Commit.Sha,
"CI_COMMIT_REF": m.Curr.Commit.Ref,

View File

@@ -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"`
SCM string `json:"scm,omitempty"`
CloneURL string `json:"clone_url,omitempty"`
CloneSSHURL string `json:"clone_url_ssh,omitempty"`
Private bool `json:"private,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"`
SCM string `json:"scm,omitempty"`
CloneURL string `json:"clone_url,omitempty"`
CloneSSHURL string `json:"clone_url_ssh,omitempty"`
Private bool `json:"private,omitempty"`
Branch string `json:"default_branch,omitempty"`
Trusted TrustedConfiguration `json:"trusted,omitempty"`
}
// Pipeline defines runtime metadata for a pipeline.
@@ -113,4 +113,10 @@ type (
// URL returns the root url of a configured forge
URL() string
}
TrustedConfiguration struct {
Network bool `json:"network,omitempty"`
Volumes bool `json:"volumes,omitempty"`
Security bool `json:"security,omitempty"`
}
)

View File

@@ -83,22 +83,22 @@ func (s *Secret) Match(event string) bool {
// 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
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
defaultClonePlugin string
trustedClonePlugins []string
securityTrustedPipeline bool
netrcOnlyTrusted bool
}
// New creates a new Compiler with options.
@@ -196,7 +196,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
}
@@ -253,7 +253,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
}

View File

@@ -169,10 +169,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
}
}

View File

@@ -30,11 +30,17 @@ 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
Security bool
}
// New creates a new Linter with options.
func New(opts ...Option) *Linter {
linter := new(Linter)
@@ -143,10 +149,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)
@@ -204,29 +208,35 @@ 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 !l.trusted.Security {
if c.Privileged {
errors = append(errors, "Insufficient privileges to use privileged mode")
}
}
if len(c.DNS) != 0 {
errors = append(errors, "Insufficient privileges to use custom dns")
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.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 len(c.NetworkMode) != 0 {
errors = append(errors, "Insufficient privileges to use network_mode")
}
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 !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 {

View File

@@ -94,7 +94,11 @@ 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,
Security: true,
})).Lint([]*linter.WorkflowConfig{{
File: testd.Title,
RawConfig: testd.Data,
Workflow: conf,

View File

@@ -18,7 +18,7 @@ package linter
type Option func(*Linter)
// WithTrusted adds the trusted option to the linter.
func WithTrusted(trusted bool) Option {
func WithTrusted(trusted TrustedConfiguration) Option {
return func(linter *Linter) {
linter.trusted = trusted
}