diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index d1f0803b7..a8ace1695 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -1,5 +1,5 @@ import { themes } from 'prism-react-renderer'; -import type {Config} from '@docusaurus/types'; +import type { Config } from '@docusaurus/types'; import type * as Preset from '@docusaurus/preset-classic'; import * as path from 'path'; @@ -14,147 +14,146 @@ const config: Config = { organizationName: 'woodpecker-ci', projectName: 'woodpecker-ci.github.io', trailingSlash: false, - themeConfig: - ({ - navbar: { - title: 'Woodpecker', - logo: { - alt: 'Woodpecker Logo', - src: 'img/logo.svg', + themeConfig: { + navbar: { + title: 'Woodpecker', + logo: { + alt: 'Woodpecker Logo', + src: 'img/logo.svg', + }, + items: [ + { + type: 'doc', + docId: 'intro', + activeBaseRegex: 'docs/(?!migrations|awesome)', + position: 'left', + label: 'Docs', }, - items: [ - { - type: 'doc', - docId: 'intro', - activeBaseRegex: 'docs/(?!migrations|awesome)', - position: 'left', - label: 'Docs', - }, - { - to: '/plugins', - position: 'left', - label: 'Plugins', - }, - { - to: '/docs/next/migrations', // Always point to newest migration guide - activeBaseRegex: 'docs/(next/)?migrations', - position: 'left', - label: 'Migrations', - }, - { - to: '/faq', - position: 'left', - label: 'FAQ', - }, - { - to: '/docs/next/awesome', // Always point to newest awesome list - activeBaseRegex: 'docs/(next/)?awesome', - position: 'left', - label: 'Awesome', - }, - { - to: '/api', - position: 'left', - label: 'API', - }, - { to: 'blog', label: 'Blog', position: 'left' }, - { - type: 'docsVersionDropdown', - position: 'right', - }, - { - href: 'https://github.com/woodpecker-ci/woodpecker', - position: 'right', - className: 'header-github-link', - 'aria-label': 'GitHub repository', - }, - { - label: '🧡 Sponsor Us', - position: 'right', - href: 'https://opencollective.com/woodpecker-ci', - }, - ], - }, - footer: { - style: 'dark', - links: [ - { - title: 'Docs', - items: [ - { - label: 'Introduction', - to: '/docs/intro', - }, - { - label: 'Usage', - to: '/docs/usage/intro', - }, - { - label: 'Server setup', - to: '/docs/administration/setup', - }, - { - label: 'FAQ', - to: '/faq', - }, - ], - }, - { - title: 'Community', - items: [ - { - label: 'Discord', - href: 'https://discord.gg/fcMQqSMXJy', - }, - { - label: 'Matrix', - href: 'https://matrix.to/#/#woodpecker:matrix.org', - }, - { - label: 'Mastodon', - href: 'https://floss.social/@WoodpeckerCI', - }, - ], - }, - { - title: 'More', - items: [ - { - label: 'Translate', - href: 'https://translate.woodpecker-ci.org/engage/woodpecker-ci/', - }, - { - label: 'GitHub', - href: 'https://github.com/woodpecker-ci/woodpecker', - }, - { - href: 'https://ci.woodpecker-ci.org/woodpecker-ci/woodpecker', - label: 'CI', - }, - ], - }, - ], - copyright: `Copyright © ${new Date().getFullYear()} Woodpecker CI. Built with Docusaurus.`, - }, - prism: { - theme: themes.github, - darkTheme: themes.dracula, - additionalLanguages: ['diff', 'json', 'docker', 'javascript', 'css', 'bash', 'nginx', 'apacheconf'], - }, - announcementBar: { - id: 'github-star', - content: ` If you like Woodpecker-CI, give us a star on GitHub ! ⭐️`, - backgroundColor: 'var(--ifm-color-primary)', - textColor: 'var(--ifm-color-gray-900)', - }, - tableOfContents: { - minHeadingLevel: 2, - maxHeadingLevel: 4, - }, - colorMode: { - respectPrefersColorScheme: true, - }, - } satisfies Preset.ThemeConfig), + { + to: '/plugins', + position: 'left', + label: 'Plugins', + }, + { + to: '/docs/next/migrations', // Always point to newest migration guide + activeBaseRegex: 'docs/(next/)?migrations', + position: 'left', + label: 'Migrations', + }, + { + to: '/faq', + position: 'left', + label: 'FAQ', + }, + { + to: '/docs/next/awesome', // Always point to newest awesome list + activeBaseRegex: 'docs/(next/)?awesome', + position: 'left', + label: 'Awesome', + }, + { + to: '/api', + position: 'left', + label: 'API', + }, + { to: 'blog', label: 'Blog', position: 'left' }, + { + type: 'docsVersionDropdown', + position: 'right', + }, + { + href: 'https://github.com/woodpecker-ci/woodpecker', + position: 'right', + className: 'header-github-link', + 'aria-label': 'GitHub repository', + }, + { + label: '🧡 Sponsor Us', + position: 'right', + href: 'https://opencollective.com/woodpecker-ci', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Introduction', + to: '/docs/intro', + }, + { + label: 'Usage', + to: '/docs/usage/intro', + }, + { + label: 'Server setup', + to: '/docs/administration/setup', + }, + { + label: 'FAQ', + to: '/faq', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Discord', + href: 'https://discord.gg/fcMQqSMXJy', + }, + { + label: 'Matrix', + href: 'https://matrix.to/#/#woodpecker:matrix.org', + }, + { + label: 'Mastodon', + href: 'https://floss.social/@WoodpeckerCI', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Translate', + href: 'https://translate.woodpecker-ci.org/engage/woodpecker-ci/', + }, + { + label: 'GitHub', + href: 'https://github.com/woodpecker-ci/woodpecker', + }, + { + href: 'https://ci.woodpecker-ci.org/woodpecker-ci/woodpecker', + label: 'CI', + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} Woodpecker CI. Built with Docusaurus.`, + }, + prism: { + theme: themes.github, + darkTheme: themes.dracula, + additionalLanguages: ['diff', 'json', 'docker', 'javascript', 'css', 'bash', 'nginx', 'apacheconf'], + }, + announcementBar: { + id: 'github-star', + content: ` If you like Woodpecker-CI, give us a star on GitHub ! ⭐️`, + backgroundColor: 'var(--ifm-color-primary)', + textColor: 'var(--ifm-color-gray-900)', + }, + tableOfContents: { + minHeadingLevel: 2, + maxHeadingLevel: 4, + }, + colorMode: { + respectPrefersColorScheme: true, + }, + } satisfies Preset.ThemeConfig, plugins: [ () => ({ name: 'docusaurus-plugin-favicon', @@ -206,7 +205,7 @@ const config: Config = { presets: [ [ '@docusaurus/preset-classic', - ({ + { docs: { sidebarPath: require.resolve('./sidebars.js'), editUrl: 'https://github.com/woodpecker-ci/woodpecker/edit/main/docs/', @@ -235,7 +234,7 @@ const config: Config = { theme: { customCss: require.resolve('./src/css/custom.css'), }, - } satisfies Preset.Options), + } satisfies Preset.Options, ], [ 'redocusaurus', @@ -265,8 +264,8 @@ const config: Config = { }), }, markdown: { - format: 'detect' - } + format: 'detect', + }, }; export default config; diff --git a/pipeline/frontend/yaml/compiler/compiler.go b/pipeline/frontend/yaml/compiler/compiler.go index b0524b0f3..b0d6c9c21 100644 --- a/pipeline/frontend/yaml/compiler/compiler.go +++ b/pipeline/frontend/yaml/compiler/compiler.go @@ -162,7 +162,10 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er Environment: c.cloneEnv, } name := fmt.Sprintf("%s_clone", c.prefix) - step := c.createProcess(name, container, backend_types.StepTypeClone) + step, err := c.createProcess(name, container, backend_types.StepTypeClone) + if err != nil { + return nil, err + } stage := new(backend_types.Stage) stage.Name = name @@ -183,7 +186,10 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er stage.Alias = container.Name name := fmt.Sprintf("%s_clone_%d", c.prefix, i) - step := c.createProcess(name, container, backend_types.StepTypeClone) + step, err := c.createProcess(name, container, backend_types.StepTypeClone) + if err != nil { + return nil, err + } // only inject netrc if it's a trusted repo or a trusted plugin if !c.netrcOnlyTrusted || c.trustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage()) { @@ -198,7 +204,10 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er } } - c.setupCache(conf, config) + err := c.setupCache(conf, config) + if err != nil { + return nil, err + } // add services steps if len(conf.Services.ContainerList) != 0 { @@ -214,7 +223,11 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er } name := fmt.Sprintf("%s_%s_%d", c.prefix, nameServices, i) - step := c.createProcess(name, container, backend_types.StepTypeService) + step, err := c.createProcess(name, container, backend_types.StepTypeService) + if err != nil { + return nil, err + } + stage.Steps = append(stage.Steps, step) } config.Stages = append(config.Stages, stage) @@ -249,7 +262,10 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er if container.IsPlugin() { stepType = backend_types.StepTypePlugin } - step := c.createProcess(name, container, stepType) + step, err := c.createProcess(name, container, stepType) + if err != nil { + return nil, err + } // inject netrc if it's a trusted repo or a trusted clone-plugin if c.trustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage()) { @@ -261,19 +277,25 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er stage.Steps = append(stage.Steps, step) } - c.setupCacheRebuild(conf, config) + err = c.setupCacheRebuild(conf, config) + if err != nil { + return nil, err + } return config, nil } -func (c *Compiler) setupCache(conf *yaml_types.Workflow, ir *backend_types.Config) { +func (c *Compiler) setupCache(conf *yaml_types.Workflow, ir *backend_types.Config) error { if c.local || len(conf.Cache) == 0 || c.cacher == nil { - return + return nil } container := c.cacher.Restore(path.Join(c.metadata.Repo.Owner, c.metadata.Repo.Name), c.metadata.Curr.Commit.Branch, conf.Cache) name := fmt.Sprintf("%s_restore_cache", c.prefix) - step := c.createProcess(name, container, backend_types.StepTypeCache) + step, err := c.createProcess(name, container, backend_types.StepTypeCache) + if err != nil { + return err + } stage := new(backend_types.Stage) stage.Name = name @@ -281,16 +303,21 @@ func (c *Compiler) setupCache(conf *yaml_types.Workflow, ir *backend_types.Confi stage.Steps = append(stage.Steps, step) ir.Stages = append(ir.Stages, stage) + + return nil } -func (c *Compiler) setupCacheRebuild(conf *yaml_types.Workflow, ir *backend_types.Config) { +func (c *Compiler) setupCacheRebuild(conf *yaml_types.Workflow, ir *backend_types.Config) error { if c.local || len(conf.Cache) == 0 || c.metadata.Curr.Event != metadata.EventPush || c.cacher == nil { - return + return nil } container := c.cacher.Rebuild(path.Join(c.metadata.Repo.Owner, c.metadata.Repo.Name), c.metadata.Curr.Commit.Branch, conf.Cache) name := fmt.Sprintf("%s_rebuild_cache", c.prefix) - step := c.createProcess(name, container, backend_types.StepTypeCache) + step, err := c.createProcess(name, container, backend_types.StepTypeCache) + if err != nil { + return err + } stage := new(backend_types.Stage) stage.Name = name @@ -298,4 +325,6 @@ func (c *Compiler) setupCacheRebuild(conf *yaml_types.Workflow, ir *backend_type stage.Steps = append(stage.Steps, step) ir.Stages = append(ir.Stages, stage) + + return nil } diff --git a/pipeline/frontend/yaml/compiler/compiler_test.go b/pipeline/frontend/yaml/compiler/compiler_test.go index 6664d6ece..0b241f5e3 100644 --- a/pipeline/frontend/yaml/compiler/compiler_test.go +++ b/pipeline/frontend/yaml/compiler/compiler_test.go @@ -94,10 +94,10 @@ func TestCompilerCompile(t *testing.T) { } tests := []struct { - name string - fronConf *yaml_types.Workflow - backConf *backend_types.Config - expErr bool + name string + fronConf *yaml_types.Workflow + backConf *backend_types.Config + expectedErr string }{{ name: "empty workflow, no clone", fronConf: &yaml_types.Workflow{SkipClone: true}, @@ -197,13 +197,24 @@ func TestCompilerCompile(t *testing.T) { }}, }}, }, + }, { + name: "workflow with missing secret", + fronConf: &yaml_types.Workflow{Steps: yaml_types.ContainerList{ContainerList: []*yaml_types.Container{{ + Name: "step", + Image: "bash", + Commands: []string{"env"}, + Secrets: yaml_types.Secrets{Secrets: []*yaml_types.Secret{{Source: "missing", Target: "missing"}}}, + }}}}, + backConf: nil, + expectedErr: "secret \"missing\" not found or not allowed to be used", }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { backConf, err := compiler.Compile(test.fronConf) - if test.expErr { + if test.expectedErr != "" { assert.Error(t, err) + assert.Equal(t, err.Error(), test.expectedErr) } else { // we ignore uuids in steps and only check if global env got set ... for _, st := range backConf.Stages { diff --git a/pipeline/frontend/yaml/compiler/convert.go b/pipeline/frontend/yaml/compiler/convert.go index 53e85f0d9..40da15152 100644 --- a/pipeline/frontend/yaml/compiler/convert.go +++ b/pipeline/frontend/yaml/compiler/convert.go @@ -21,7 +21,6 @@ import ( "strings" "github.com/google/uuid" - "github.com/rs/zerolog/log" backend_types "github.com/woodpecker-ci/woodpecker/pipeline/backend/types" "github.com/woodpecker-ci/woodpecker/pipeline/frontend/metadata" @@ -30,7 +29,7 @@ import ( "github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/utils" ) -func (c *Compiler) createProcess(name string, container *yaml_types.Container, stepType backend_types.StepType) *backend_types.Step { +func (c *Compiler) createProcess(name string, container *yaml_types.Container, stepType backend_types.StepType) (*backend_types.Step, error) { var ( uuid = uuid.New() @@ -90,7 +89,7 @@ func (c *Compiler) createProcess(name string, container *yaml_types.Container, s } if err := settings.ParamsToEnv(container.Settings, environment, pluginSecrets.toStringMap()); err != nil { - log.Error().Err(err).Msg("paramsToEnv") + return nil, err } } @@ -112,6 +111,8 @@ func (c *Compiler) createProcess(name string, container *yaml_types.Container, s secret, ok := c.secrets[strings.ToLower(requested.Source)] if ok && secret.Available(container) { environment[strings.ToUpper(requested.Target)] = secret.Value + } else { + return nil, fmt.Errorf("secret %q not found or not allowed to be used", requested.Source) } } @@ -213,7 +214,7 @@ func (c *Compiler) createProcess(name string, container *yaml_types.Container, s IpcMode: ipcMode, Ports: ports, BackendOptions: backendOptions, - } + }, nil } func (c *Compiler) stepWorkdir(container *yaml_types.Container) string {