Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ef4f643
test env
ljuboops257 Nov 12, 2025
25f6f17
new structure
ljuboops257 Nov 18, 2025
7b24c3e
revert ljubon-org changes
ljuboops257 Nov 18, 2025
ffd521b
update mermaid
ljubon Nov 18, 2025
e57c35c
Update docs/DEVELOPERS_GUIDE.md
ljuboops257 Nov 24, 2025
f12635a
Update docs/DEVELOPERS_GUIDE.md
ljuboops257 Nov 24, 2025
0c9ed54
Update docs/DEVELOPERS_GUIDE.md
ljuboops257 Nov 24, 2025
cf370bd
Update docs/DEVELOPERS_GUIDE.md
ljuboops257 Nov 24, 2025
cb8cf2a
Update docs/DEVELOPERS_GUIDE.md
ljuboops257 Nov 24, 2025
38953f7
move out import control from DEVELOPERS_GUIDE
ljuboops257 Dec 25, 2025
33c8288
fix wait_timer description - minutes instead of seconds
ljuboops257 Dec 25, 2025
32986af
out of scope of PR
ljuboops257 Dec 25, 2025
f4bda55
out of scope of PR - move to docs pr
ljuboops257 Dec 25, 2025
d17e72e
out of scope of PR
ljuboops257 Dec 25, 2025
e6b4622
move out envs from repositories.go
ljuboops257 Dec 25, 2025
a92f7a3
Merge main into gcss-1135
dev-milos Jul 9, 2026
62a61ba
GCSS-1135: validate environments schema and fix wait_timer unit
dev-milos Jul 9, 2026
bd4b61c
GCSS-1135: label deployment-policy resources in plan summary
dev-milos Jul 9, 2026
742d74b
GCSS-1135: address review feedback and shrink blast radius
dev-milos Jul 9, 2026
666d3bd
GCSS-1135: reject >6 environment reviewers on import
dev-milos Jul 10, 2026
b76ec66
GCSS-1135: reuse go-github ListDeploymentBranchPolicies; restore 2 re…
dev-milos Jul 10, 2026
33daa10
GCSS-1135: address review round 2 (Ivan)
dev-milos Jul 13, 2026
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
3 changes: 3 additions & 0 deletions .github/actions/graformer/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ runs:
return `${resourceChange.type} :: ${match[1]}/${actualChange.pattern}`;
}else if(resourceChange.type === 'github_repository_environment'){
return `${resourceChange.type} :: ${actualChange.repository}/${actualChange.environment}`;
}else if(resourceChange.type === 'github_repository_environment_deployment_policy'){
const pattern = actualChange.branch_pattern || actualChange.tag_pattern;
return `${resourceChange.type} :: ${actualChange.repository}/${actualChange.environment} (${pattern})`;
}else if(resourceChange.type === 'github_repository_custom_property'){
return `${resourceChange.type} :: ${actualChange.repository}/${actualChange.property_name}`;
} else {
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/promote-imported-configs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
mkdir -p "$dst"

find "$src" -type f -name '*.yaml' | while read file; do
yq '. |= ( with(select(.rulesets[] != null); .rulesets[] |= del(.id)) | with(select(.rulesets[] == null); .) )' -i $file
yq '. |= ( with(select(.rulesets[] != null); .rulesets[] |= del(.id)) | with(select(.rulesets[] == null); .) ) | del(.environments[].deployment_policy.branch_policy_ids) | del(.environments[].deployment_policy.tag_policy_ids)' -i $file
done

find "$src" -maxdepth 1 -type f \( -name "*.yaml" -o -name ".*.yaml" \) -print -exec mv {} "$dst" \;
Expand Down
81 changes: 81 additions & 0 deletions .schemas/repository-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,81 @@
"ref_name"
]
},
"DeploymentPolicy": {
"properties": {
"policy_type": {
"type": "string",
"enum": [
"protected_branches",
"selected_branches_and_tags"
]
},
"branch_patterns": {
"items": {
"type": "string"
},
"type": "array"
},
"tag_patterns": {
"items": {
"type": "string"
},
"type": "array"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"policy_type"
]
},
"Environment": {
"properties": {
"environment": {
"type": "string"
},
"wait_timer": {
"type": "integer",
"maximum": 43200,
"minimum": 0
},
"can_admins_bypass": {
"type": "boolean"
},
"prevent_self_review": {
"type": "boolean"
},
"reviewers": {
"$ref": "#/$defs/EnvironmentReviewers"
},
"deployment_policy": {
"$ref": "#/$defs/DeploymentPolicy"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"environment"
]
},
"EnvironmentReviewers": {
"properties": {
"teams": {
"items": {
"type": "string"
},
"type": "array"
},
"users": {
"items": {
"type": "string"
},
"type": "array"
}
},
"additionalProperties": false,
"type": "object"
},
"HighIntegrityConfig": {
"properties": {
"enabled": {
Expand Down Expand Up @@ -421,6 +496,12 @@
},
"type": "array"
},
"environments": {
"items": {
"$ref": "#/$defs/Environment"
},
"type": "array"
},
"custom_properties": {
"additionalProperties": {
"type": "string"
Expand Down
25 changes: 24 additions & 1 deletion DEVELOPERS_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ These are the primary configuration options for each repository.

- **`vulnerability_alerts_enabled`**: *(optional, boolean)* If `true`, vulnerability alerts are enabled.

- **`environments`**: *(optional, object[] [Environment](#environment-configuration))* Configuration for repository environments. Requires `feature_github_environments: true` in the import config. When imported, environments are managed by Terraform.

- **`branch_protections_v4`**: *(optional, object[] [BranchProtectionV4](#branch-protection-configuration-v4))* Configuration for branch protection rules.

- **`custom_properties`**: *(optional, map[string]string)* A map of GitHub organization custom property names to their string values. See [Custom Properties](#custom-properties).
Expand All @@ -126,6 +128,27 @@ high_integrity:
enabled: true
```

## Environment Configuration

### Environment Fields

- **`environment`**: *(required, string)* Environment name
- **`wait_timer`**: *(optional, int)* Delay in minutes (max 43200, i.e. 30 days)
- **`can_admins_bypass`**: *(optional, bool)* Admin bypass allowed (default: true)
- **`prevent_self_review`**: *(optional, bool)* Prevent self-approval (default: false)
- **`reviewers`**: *(optional, object)* At most 6 reviewers total across `users` and `teams`.
- **`users`**: *(string[])* GitHub usernames
- **`teams`**: *(string[])* Team slugs

> ⚠️ **Team access requirement**
>
> Teams specified as reviewers must have repository access first, otherwise Terraform applies successfully but the teams are not added as reviewers and the next plan/apply keeps showing them as proposed changes.

- **`deployment_policy`**: *(optional, object)* Controls which branches/tags can deploy to this environment.
- **`policy_type`**: *(required, string)* One of `protected_branches` (only protected branches can deploy) or `selected_branches_and_tags` (specific branch/tag patterns can deploy).
- **`branch_patterns`**: *(optional, string[])* Branch patterns (e.g. `["main", "release/*"]`). Only used when `policy_type` is `selected_branches_and_tags`; omit otherwise.
- **`tag_patterns`**: *(optional, string[])* Tag patterns (e.g. `["v*"]`). Only used when `policy_type` is `selected_branches_and_tags`; omit otherwise.

## Custom Properties

[GitHub organization custom properties](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization) allow organizations to attach structured metadata to repositories — such as lifecycle stage, team ownership, compliance classification, or any other organization-defined attribute. They are defined once at the organization level and can then be set per repository.
Expand Down Expand Up @@ -382,4 +405,4 @@ Options for configuring required status checks in V4.

- **`strict`**: *(optional, boolean)* If `true`, strict status checks are enforced.

- **`contexts`**: *(optional, string[])* A list of required status check contexts.
- **`contexts`**: *(optional, string[])* A list of required status check contexts.
10 changes: 9 additions & 1 deletion feature/github-repo-importer/cmd/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/gr-oss-devops/github-repo-importer/pkg/github"
)

var importConfigPath string

var importCmd = &cobra.Command{
Use: "import [owner/repo]",
Short: "Import command reads all repository details and creates a configuration yaml file",
Expand All @@ -18,7 +20,12 @@ var importCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
repository := args[0]

repo, err := github.ImportRepo(repository)
cfg, err := DecodeConfiguration(importConfigPath)
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}

repo, err := github.ImportRepo(repository, cfg)
if err != nil {
return err
}
Expand All @@ -33,4 +40,5 @@ var importCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(importCmd)
importCmd.Flags().StringVarP(&importConfigPath, "config", "c", "./import-config.yaml", "Path to the import config file (default: ./import-config.yaml)")
}
2 changes: 2 additions & 0 deletions feature/github-repo-importer/pkg/compare/compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ func hashNormalizedYamlFile(path string) (string, error) {
if node.Kind == yaml.DocumentNode && len(node.Content) > 0 {
root := node.Content[0]
removeKey(root, "id")
removeKey(root, "branch_policy_ids")
removeKey(root, "tag_policy_ids")
sortMappingNode(root)
}

Expand Down
9 changes: 5 additions & 4 deletions feature/github-repo-importer/pkg/github/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import (
)

type Config struct {
IsPublic *bool `yaml:"is_public,omitempty"`
IgnoredRepos []string `yaml:"ignored_repos,omitempty"`
SelectedRepos []string `yaml:"selected_repos,omitempty"`
PageSize *int `yaml:"page_size,omitempty"`
IsPublic *bool `yaml:"is_public,omitempty"`
IgnoredRepos []string `yaml:"ignored_repos,omitempty"`
SelectedRepos []string `yaml:"selected_repos,omitempty"`
PageSize *int `yaml:"page_size,omitempty"`
FeatureGithubEnvironments *bool `yaml:"feature_github_environments,omitempty"`
}

func (c *Config) Validate() error {
Expand Down
23 changes: 23 additions & 0 deletions feature/github-repo-importer/pkg/github/environments.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package github

type Environment struct {
Environment string `yaml:"environment" jsonschema:"required"`
WaitTimer *int `yaml:"wait_timer,omitempty" jsonschema:"minimum=0,maximum=43200"`
CanAdminsBypass *bool `yaml:"can_admins_bypass,omitempty"`
PreventSelfReview *bool `yaml:"prevent_self_review,omitempty"`
Reviewers *EnvironmentReviewers `yaml:"reviewers,omitempty"`
DeploymentPolicy *DeploymentPolicy `yaml:"deployment_policy,omitempty"`
}

type EnvironmentReviewers struct {
Teams []string `yaml:"teams,omitempty"`
Users []string `yaml:"users,omitempty"`
}

type DeploymentPolicy struct {
PolicyType string `yaml:"policy_type" jsonschema:"required,enum=protected_branches,enum=selected_branches_and_tags"`
BranchPatterns []string `yaml:"branch_patterns,omitempty"`
TagPatterns []string `yaml:"tag_patterns,omitempty"`
BranchPolicyIDs map[string]int64 `yaml:"branch_policy_ids,omitempty" jsonschema:"-"`
TagPolicyIDs map[string]int64 `yaml:"tag_policy_ids,omitempty" jsonschema:"-"`
}
Loading
Loading