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

Tag pipeline with source information #4796

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions cmd/agent/core/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (

"go.woodpecker-ci.org/woodpecker/v3/agent"
agent_rpc "go.woodpecker-ci.org/woodpecker/v3/agent/rpc"
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend"
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc"
Expand Down Expand Up @@ -251,6 +252,9 @@ func run(ctx context.Context, c *cli.Command, backends []types.Backend) error {
"backend": backendEngine.Name(),
"repo": "*", // allow all repos by default
}
for _, label := range pipeline.InternalLabels {
labels[label] = "*"
}
// ... and let it overwrite by custom ones
maps.Copy(labels, customLabels)

Expand Down
4 changes: 2 additions & 2 deletions cmd/agent/core/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func TestStringSliceAddToMap(t *testing.T) {
name: "empty string in slice",
sl: []string{"foo=bar", "", "baz=qux"},
m: make(map[string]string),
expected: map[string]string{},
err: true,
expected: map[string]string{"foo": "bar", "baz": "qux"},
err: false,
},
}

Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/migrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ To enhance the usability of Woodpecker and meet evolving security standards, occ

## `next`

- No changes
- (Kubernetes) Deprecated `step` label on pod in favor of new namespaced label `woodpecker-ci.org/step`. The `step` label will be removed in a future update.

## 3.0.0

Expand Down
24 changes: 21 additions & 3 deletions pipeline/backend/kubernetes/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package kubernetes
import (
"context"
"fmt"
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
"maps"
"strings"

Expand All @@ -31,9 +32,12 @@ import (
)

const (
StepLabel = "step"
podPrefix = "wp-"
defaultFSGroup int64 = 1000
// StepLabelLegacy is the legacy label name from before the introduction of the woodpecker-ci.org namespace.
// This will be removed in the future.
StepLabelLegacy = "step"
StepLabel = "woodpecker-ci.org/step"
podPrefix = "wp-"
defaultFSGroup int64 = 1000
)

func mkPod(step *types.Step, config *config, podName, goos string, options BackendOptions) (*v1.Pod, error) {
Expand Down Expand Up @@ -100,21 +104,35 @@ func podLabels(step *types.Step, config *config, options BackendOptions) (map[st
var err error
labels := make(map[string]string)

for k, v := range step.WorkflowLabels {
// Only copy user labels if allowed by agent config.
// Internal labels are filtered on the server-side.
if config.PodLabelsAllowFromStep || strings.HasPrefix(k, pipeline.InternalLabelPrefix) {
labels[k] = v
}
}

if len(options.Labels) > 0 {
if config.PodLabelsAllowFromStep {
log.Trace().Msgf("using labels from the backend options: %v", options.Labels)
// TODO should we filter out label with internal prefix?
maps.Copy(labels, options.Labels)
} else {
log.Debug().Msg("Pod labels were defined in backend options, but its using disallowed by instance configuration")
}
}
if len(config.PodLabels) > 0 {
log.Trace().Msgf("using labels from the configuration: %v", config.PodLabels)
// TODO should we filter out label with internal prefix?
maps.Copy(labels, config.PodLabels)
}
if step.Type == types.StepTypeService {
labels[ServiceLabel], _ = serviceName(step)
}
labels[StepLabelLegacy], err = stepLabel(step)
if err != nil {
return labels, err
}
labels[StepLabel], err = stepLabel(step)
if err != nil {
return labels, err
Expand Down
12 changes: 8 additions & 4 deletions pipeline/backend/kubernetes/pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ func TestTinyPod(t *testing.T) {
"namespace": "woodpecker",
"creationTimestamp": null,
"labels": {
"step": "build-via-gradle"
"step": "build-via-gradle",
"woodpecker-ci.org/step": "build-via-gradle"
}
},
"spec": {
Expand Down Expand Up @@ -153,7 +154,8 @@ func TestFullPod(t *testing.T) {
"labels": {
"app": "test",
"part-of": "woodpecker-ci",
"step": "go-test"
"step": "go-test",
"woodpecker-ci.org/step": "go-test"
},
"annotations": {
"apps.kubernetes.io/pod-index": "0",
Expand Down Expand Up @@ -447,7 +449,8 @@ func TestScratchPod(t *testing.T) {
"namespace": "woodpecker",
"creationTimestamp": null,
"labels": {
"step": "curl-google"
"step": "curl-google",
"woodpecker-ci.org/step": "curl-google"
}
},
"spec": {
Expand Down Expand Up @@ -492,7 +495,8 @@ func TestSecrets(t *testing.T) {
"namespace": "woodpecker",
"creationTimestamp": null,
"labels": {
"step": "test-secrets"
"step": "test-secrets",
"woodpecker-ci.org/step": "test-secrets"
}
},
"spec": {
Expand Down
17 changes: 15 additions & 2 deletions pipeline/backend/kubernetes/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"encoding/json"
"fmt"
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
"strings"

"github.com/distribution/reference"
Expand Down Expand Up @@ -210,7 +211,7 @@ func mkRegistrySecret(step *types.Step, config *config) (*v1.Secret, error) {
return nil, err
}

labels, err := registrySecretLabels(step)
labels, err := registrySecretLabels(step, config)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -251,13 +252,25 @@ func registrySecretName(step *types.Step) (string, error) {
return podName(step)
}

func registrySecretLabels(step *types.Step) (map[string]string, error) {
func registrySecretLabels(step *types.Step, config *config) (map[string]string, error) {
var err error
labels := make(map[string]string)

for k, v := range step.WorkflowLabels {
// Only copy user labels if allowed by agent config.
// Internal labels are filtered on the server-side.
if config.PodLabelsAllowFromStep || strings.HasPrefix(k, pipeline.InternalLabelPrefix) {
labels[k] = v
}
}

if step.Type == types.StepTypeService {
labels[ServiceLabel], _ = serviceName(step)
}
labels[StepLabelLegacy], err = stepLabel(step)
if err != nil {
return labels, err
}
labels[StepLabel], err = stepLabel(step)
if err != nil {
return labels, err
Expand Down
3 changes: 2 additions & 1 deletion pipeline/backend/kubernetes/secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ func TestRegistrySecret(t *testing.T) {
"namespace": "woodpecker",
"creationTimestamp": null,
"labels": {
"step": "go-test"
"step": "go-test",
"woodpecker-ci.org/step": "go-test"
}
},
"type": "kubernetes.io/dockerconfigjson",
Expand Down
1 change: 1 addition & 0 deletions pipeline/backend/types/step.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type Step struct {
NetworkMode string `json:"network_mode,omitempty"`
Ports []Port `json:"ports,omitempty"`
BackendOptions map[string]any `json:"backend_options,omitempty"`
WorkflowLabels map[string]string `json:"workflow_labels,omitempty"`
}

// StepType identifies the type of step.
Expand Down
10 changes: 10 additions & 0 deletions pipeline/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,14 @@ const (
// Store no more than 1mb in a log-line as 4mb is the limit of a grpc message
// and log-lines needs to be parsed by the browsers later on.
MaxLogLineLength int = 1 * 1024 * 1024 // 1mb

InternalLabelPrefix string = "woodpecker-ci.org"
LabelForgeRemoteID string = InternalLabelPrefix + "/forge-id"
LabelRepoForgeID string = InternalLabelPrefix + "/repo-forge-id"
LabelRepoID string = InternalLabelPrefix + "/repo-id"
LabelRepoName string = InternalLabelPrefix + "/repo-name"
LabelBranch string = InternalLabelPrefix + "/branch"
LabelOrgID string = InternalLabelPrefix + "/org-id"
)

var InternalLabels = []string{LabelForgeRemoteID, LabelRepoForgeID, LabelRepoID, LabelRepoName, LabelBranch, LabelOrgID}
8 changes: 4 additions & 4 deletions pipeline/frontend/yaml/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er
for k, v := range c.cloneEnv {
container.Environment[k] = v
}
step, err := c.createProcess(container, backend_types.StepTypeClone)
step, err := c.createProcess(container, conf, backend_types.StepTypeClone)
if err != nil {
return nil, err
}
Expand All @@ -189,7 +189,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er

stage := new(backend_types.Stage)

step, err := c.createProcess(container, backend_types.StepTypeClone)
step, err := c.createProcess(container, conf, backend_types.StepTypeClone)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -218,7 +218,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er
return nil, err
}

step, err := c.createProcess(container, backend_types.StepTypeService)
step, err := c.createProcess(container, conf, backend_types.StepTypeService)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -246,7 +246,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er
if container.IsPlugin() {
stepType = backend_types.StepTypePlugin
}
step, err := c.createProcess(container, stepType)
step, err := c.createProcess(container, conf, stepType)
if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion pipeline/frontend/yaml/compiler/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const (
DefaultWorkspaceBase = pluginWorkspaceBase
)

func (c *Compiler) createProcess(container *yaml_types.Container, stepType backend_types.StepType) (*backend_types.Step, error) {
func (c *Compiler) createProcess(container *yaml_types.Container, workflow *yaml_types.Workflow, stepType backend_types.StepType) (*backend_types.Step, error) {
var (
uuid = ulid.Make()

Expand Down Expand Up @@ -181,6 +181,7 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe
NetworkMode: networkMode,
Ports: ports,
BackendOptions: container.BackendOptions,
WorkflowLabels: workflow.Labels,
}, nil
}

Expand Down
23 changes: 23 additions & 0 deletions server/pipeline/stepbuilder/stepBuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ package stepbuilder

import (
"fmt"
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
"maps"
"path/filepath"
"strconv"
"strings"

"github.com/oklog/ulid/v2"
Expand Down Expand Up @@ -194,6 +196,27 @@ func (b *StepBuilder) genItemForWorkflow(workflow *model.Workflow, axis matrix.A
maps.Copy(item.Labels, b.DefaultLabels)
}

// "woodpecker-ci.org" namespace is reserved for internal use
for key := range item.Labels {
if strings.HasPrefix(key, pipeline.InternalLabelPrefix) {
log.Debug().Str("forge", b.Forge.Name()).Str("repo", b.Repo.FullName).Str("label", key).Msg("dropped pipeline label with reserved prefix woodpecker-ci.org")
delete(item.Labels, key)
}
}

Copy link
Member

Choose a reason for hiding this comment

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

Those labels should not be mixed with the existing labels as those are used for filtering etc. Can we not add a new struct field e.g. item.InternalLabels or item.MetadataLabels here already?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would say they are also useful for filtering, not the originally intended use, but still useful

Copy link
Contributor

Choose a reason for hiding this comment

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

I also think we can keep them. But then you have to add some docs that using woodpecker-ci.org prefix is not allowed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No problem, I will add it to the docs

item.Labels[pipeline.LabelForgeRemoteID] = b.Forge.Name()
item.Labels[pipeline.LabelRepoForgeID] = string(b.Repo.ForgeRemoteID)
item.Labels[pipeline.LabelRepoID] = strconv.FormatInt(b.Repo.ID, 10)
item.Labels[pipeline.LabelRepoName] = b.Repo.Name
item.Labels[pipeline.LabelBranch] = b.Repo.Branch
item.Labels[pipeline.LabelOrgID] = strconv.FormatInt(b.Repo.OrgID, 10)

for stageI := range item.Config.Stages {
for stepI := range item.Config.Stages[stageI].Steps {
item.Config.Stages[stageI].Steps[stepI].WorkflowLabels = item.Labels
}
}

return item, errorsAndWarnings
}

Expand Down