diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 635bf6a..fab6321 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,6 +48,7 @@ jobs: with: distribution: goreleaser version: latest + args: release --rm-dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile index ff64d4a..ca51877 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,4 +16,4 @@ COPY --from=deps /usr/bin/xargs /usr/bin/xargs COPY --from=deps /lib /lib COPY --from=deps /usr/lib /usr/lib -CMD ["/codeowners-validator"] +ENTRYPOINT ["/codeowners-validator"] diff --git a/README.md b/README.md index ccb1117..fa04f80 100644 --- a/README.md +++ b/README.md @@ -132,10 +132,11 @@ Use the following environment variables to configure the application: | CHECK_FAILURE_LEVEL | `warning` | Defines the level on which the application should treat check issues as failures. Defaults to `warning`, which treats both errors and warnings as failures, and exits with error code 3. Possible values are `error` and `warning`. | | OWNER_CHECKER_REPOSITORY * | | The owner and repository name separated by slash. For example, gh-codeowners/codeowners-samples. Used to check if GitHub owner is in the given organization. | | OWNER_CHECKER_IGNORED_OWNERS | `@ghost` | The comma-separated list of owners that should not be validated. Example: `"@owner1,@owner2,@org/team1,example@email.com"`. | -| OWNER_CHECKER_ALLOW_UNOWNED_PATTERNS | `true` | Specifies whether CODEOWNERS may have unowned files. For example:

`/infra/oncall-rotator/ @sre-team`
`/infra/oncall-rotator/oncall-config.yml`

The `/infra/oncall-rotator/oncall-config.yml` file is not owned by anyone. | +| OWNER_CHECKER_ALLOW_UNOWNED_PATTERNS | `true` | Specifies whether CODEOWNERS may have unowned files. For example:

`/infra/oncall-rotator/ @sre-team`
`/infra/oncall-rotator/oncall-config.yml`

The `/infra/oncall-rotator/oncall-config.yml` file is not owned by anyone. | | OWNER_CHEKER_OWNERS_MUST_BE_TEAMS | `false` | Specifies whether only teams are allowed as owners of files. | | NOT_OWNED_CHECKER_SKIP_PATTERNS | - | The comma-separated list of patterns that should be ignored by `not-owned-checker`. For example, you can specify `*` and as a result, the `*` pattern from the **CODEOWNERS** file will be ignored and files owned by this pattern will be reported as unowned unless a later specific pattern will match that path. It's useful because often we have default owners entry at the begging of the CODOEWNERS file, e.g. `* @global-owner1 @global-owner2` | -| NOT_OWNED_CHECKER_SUBDIRECTORIES | - | The comma-separated list of subdirectories to check in `not-owned-checker`. When specified, only files in the listed subdirectories will be checked if they do not have specified owners in CODEOWNERS. | +| NOT_OWNED_CHECKER_SUBDIRECTORIES | - | The comma-separated list of subdirectories to check in `not-owned-checker`. When specified, only files in the listed subdirectories will be checked if they do not have specified owners in CODEOWNERS. | +| NOT_OWNED_CHECKER_TRUST_WORKSPACE | `false` | Specifies whether the repository path should be marked as safe. See: https://github.com/actions/checkout/issues/766. | * - Required @@ -143,11 +144,11 @@ Use the following environment variables to configure the application: Application exits with different status codes which allow you to easily distinguish between error categories. -| Code | Description | -|:-----:|:------------| -| **1** | The application startup failed due to the wrong configuration or internal error. | +| Code | Description | +|:-----:|:------------------------------------------------------------------------------------------| +| **1** | The application startup failed due to the wrong configuration or internal error. | | **2** | The application was closed because the OS sends a termination signal (SIGINT or SIGTERM). | -| **3** | The CODEOWNERS validation failed - executed checks found some issues. | +| **3** | The CODEOWNERS validation failed - executed checks found some issues. | ## Contributing diff --git a/action.yml b/action.yml index 199dbf1..b02de7c 100644 --- a/action.yml +++ b/action.yml @@ -44,23 +44,28 @@ inputs: default: "${{ github.repository }}" owner_checker_ignored_owners: - description: "The comma-separated list of owners that should not be validated. Example: @owner1,@owner2,@org/team1,example@email.com." + description: "The comma-separated list of owners that should not be validated. Example: @owner1,@owner2,@org/team1,example@email.com." required: false owner_checker_allow_unowned_patterns: - description: "Specifies whether CODEOWNERS may have unowned files. For example, `/infra/oncall-rotator/oncall-config.yml` doesn't have owner and this is not reported." + description: "Specifies whether CODEOWNERS may have unowned files. For example, `/infra/oncall-rotator/oncall-config.yml` doesn't have owner and this is not reported." default: "true" required: false owner_checker_owners_must_be_teams: - description: "Specifies whether only teams are allowed as owners of files." + description: "Specifies whether only teams are allowed as owners of files." default: "false" required: false not_owned_checker_subdirectories: - description: "Only check listed subdirectories for CODEOWNERS ownership that don't have owners." + description: "Only check listed subdirectories for CODEOWNERS ownership that don't have owners." required: false + not_owned_checker_trust_workspace: + description: "Specifies whether the repository path should be marked as safe. See: https://github.com/actions/checkout/issues/766" + required: false + default: "true" + runs: using: 'docker' image: 'docker://ghcr.io/mszostok/codeowners-validator:v0.7.3' diff --git a/internal/check/not_owned_file.go b/internal/check/not_owned_file.go index da73647..dbc2904 100644 --- a/internal/check/not_owned_file.go +++ b/internal/check/not_owned_file.go @@ -16,6 +16,10 @@ import ( ) type NotOwnedFileConfig struct { + // TrustWorkspace sets the global gif config + // to trust a given repository path + // see: https://github.com/actions/checkout/issues/766 + TrustWorkspace bool `envconfig:"default=false"` SkipPatterns []string `envconfig:"optional"` Subdirectories []string `envconfig:"optional"` } @@ -23,6 +27,7 @@ type NotOwnedFileConfig struct { type NotOwnedFile struct { skipPatterns map[string]struct{} subDirectories []string + trustWorkspace bool } func NewNotOwnedFile(cfg NotOwnedFileConfig) *NotOwnedFile { @@ -34,6 +39,7 @@ func NewNotOwnedFile(cfg NotOwnedFileConfig) *NotOwnedFile { return &NotOwnedFile{ skipPatterns: skip, subDirectories: cfg.Subdirectories, + trustWorkspace: cfg.TrustWorkspace, } } @@ -51,6 +57,10 @@ func (c *NotOwnedFile) Check(ctx context.Context, in Input) (output Output, err patterns := c.patternsToBeIgnored(in.CodeownersEntries) + if err := c.trustWorkspaceIfNeeded(in.RepoDir); err != nil { + return Output{}, err + } + statusOut, err := c.GitCheckStatus(in.RepoDir) if err != nil { return Output{}, err @@ -187,6 +197,20 @@ func (c *NotOwnedFile) GitListFiles(repoDir string) (string, error) { return string(stdout), nil } +func (c *NotOwnedFile) trustWorkspaceIfNeeded(repo string) error { + if !c.trustWorkspace { + return nil + } + + gitadd := pipe.Exec("git", "config", "--global", "--add", "safe.directory", repo) + _, stderr, err := pipe.DividedOutput(gitadd) + if err != nil { + return errors.Wrap(err, string(stderr)) + } + + return nil +} + func (c *NotOwnedFile) skipPatternsList() string { list := make([]string, 0, len(c.skipPatterns)) for k := range c.skipPatterns { @@ -206,7 +230,7 @@ func (c *NotOwnedFile) ListFormatFunc(es []string) string { return strings.Join(points, "\n") } -// Name returns human readable name of the validator +// Name returns human-readable name of the validator func (NotOwnedFile) Name() string { return "[Experimental] Not Owned File Checker" } diff --git a/internal/check/valid_owner.go b/internal/check/valid_owner.go index 6858ebd..e1d1241 100644 --- a/internal/check/valid_owner.go +++ b/internal/check/valid_owner.go @@ -20,6 +20,9 @@ var reqScopes = map[github.Scope]struct{}{ } type ValidOwnerConfig struct { + // Repository represents the GitHub repository against which + // the external checks like teams and members validation should be executed. + // It is in form 'owner/repository'. Repository string // IgnoredOwners contains a list of owners that should not be validated. // Defaults to @ghost.