feat: add comprehensive security scanning and EditorConfig integration

- Add govulncheck, Snyk, and Trivy vulnerability scanning
- Create security workflow for automated scanning on push/PR/schedule
- Add gitleaks for secrets detection and prevention
- Implement EditorConfig linting with eclint and editorconfig-checker
- Update Makefile with security and formatting targets
- Create SECURITY.md with vulnerability reporting guidelines
- Configure Dependabot for automated dependency updates
- Fix all EditorConfig violations across codebase
- Update Go version to 1.23.10 to address stdlib vulnerabilities
- Add tests for internal/helpers package (80% coverage)
- Remove deprecated functions and migrate to error-returning patterns
- Fix YAML indentation in test fixtures to resolve test failures
This commit is contained in:
2025-08-03 20:12:18 +03:00
parent e6c3e09a7f
commit ce02d36929
53 changed files with 2400 additions and 590 deletions

View File

@@ -5,127 +5,179 @@ package testutil
// GitHubReleaseResponse is a mock GitHub release API response.
const GitHubReleaseResponse = `{
"id": 123456,
"tag_name": "v4.1.1",
"name": "v4.1.1",
"body": "## What's Changed\n* Fix checkout bug\n* Improve performance",
"draft": false,
"prerelease": false,
"created_at": "2023-11-01T10:00:00Z",
"published_at": "2023-11-01T10:00:00Z",
"tarball_url": "https://api.github.com/repos/actions/checkout/tarball/v4.1.1",
"zipball_url": "https://api.github.com/repos/actions/checkout/zipball/v4.1.1"
"id": 123456,
"tag_name": "v4.1.1",
"name": "v4.1.1",
"body": "## What's Changed\n* Fix checkout bug\n* Improve performance",
"draft": false,
"prerelease": false,
"created_at": "2023-11-01T10:00:00Z",
"published_at": "2023-11-01T10:00:00Z",
"tarball_url": "https://api.github.com/repos/actions/checkout/tarball/v4.1.1",
"zipball_url": "https://api.github.com/repos/actions/checkout/zipball/v4.1.1"
}`
// GitHubTagResponse is a mock GitHub tag API response.
const GitHubTagResponse = `{
"name": "v4.1.1",
"zipball_url": "https://github.com/actions/checkout/zipball/v4.1.1",
"tarball_url": "https://github.com/actions/checkout/tarball/v4.1.1",
"commit": {
"sha": "8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e",
"url": "https://api.github.com/repos/actions/checkout/commits/8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e"
},
"node_id": "REF_kwDOAJy2KM9yZXJlZnMvdGFncy92NC4xLjE"
"name": "v4.1.1",
"zipball_url": "https://github.com/actions/checkout/zipball/v4.1.1",
"tarball_url": "https://github.com/actions/checkout/tarball/v4.1.1",
"commit": {
"sha": "8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e",
"url": "https://api.github.com/repos/actions/checkout/commits/8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e"
},
"node_id": "REF_kwDOAJy2KM9yZXJlZnMvdGFncy92NC4xLjE"
}`
// GitHubRepoResponse is a mock GitHub repository API response.
const GitHubRepoResponse = `{
"id": 216219028,
"name": "checkout",
"full_name": "actions/checkout",
"description": "Action for checking out a repo",
"private": false,
"html_url": "https://github.com/actions/checkout",
"clone_url": "https://github.com/actions/checkout.git",
"git_url": "git://github.com/actions/checkout.git",
"ssh_url": "git@github.com:actions/checkout.git",
"default_branch": "main",
"created_at": "2019-10-16T19:40:57Z",
"updated_at": "2023-11-01T10:00:00Z",
"pushed_at": "2023-11-01T09:30:00Z",
"stargazers_count": 4521,
"watchers_count": 4521,
"forks_count": 1234,
"open_issues_count": 42,
"topics": ["github-actions", "checkout", "git"]
"id": 216219028,
"name": "checkout",
"full_name": "actions/checkout",
"description": "Action for checking out a repo",
"private": false,
"html_url": "https://github.com/actions/checkout",
"clone_url": "https://github.com/actions/checkout.git",
"git_url": "git://github.com/actions/checkout.git",
"ssh_url": "git@github.com:actions/checkout.git",
"default_branch": "main",
"created_at": "2019-10-16T19:40:57Z",
"updated_at": "2023-11-01T10:00:00Z",
"pushed_at": "2023-11-01T09:30:00Z",
"stargazers_count": 4521,
"watchers_count": 4521,
"forks_count": 1234,
"open_issues_count": 42,
"topics": ["github-actions", "checkout", "git"]
}`
// GitHubCommitResponse is a mock GitHub commit API response.
const GitHubCommitResponse = `{
"sha": "8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e",
"node_id": "C_kwDOAJy2KNoAKDhmNGI3Zjg0YmQ1NzliOTVkN2YwYjkwZjhkOGI2ZTVkOWI4YTdmNmU",
"commit": {
"message": "Fix checkout bug and improve performance",
"author": {
"name": "GitHub Actions",
"email": "actions@github.com",
"date": "2023-11-01T09:30:00Z"
},
"committer": {
"name": "GitHub Actions",
"email": "actions@github.com",
"date": "2023-11-01T09:30:00Z"
}
},
"html_url": "https://github.com/actions/checkout/commit/8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e"
"sha": "8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e",
"node_id": "C_kwDOAJy2KNoAKDhmNGI3Zjg0YmQ1NzliOTVkN2YwYjkwZjhkOGI2ZTVkOWI4YTdmNmU",
"commit": {
"message": "Fix checkout bug and improve performance",
"author": {
"name": "GitHub Actions",
"email": "actions@github.com",
"date": "2023-11-01T09:30:00Z"
},
"committer": {
"name": "GitHub Actions",
"email": "actions@github.com",
"date": "2023-11-01T09:30:00Z"
}
},
"html_url": "https://github.com/actions/checkout/commit/8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e"
}`
// GitHubRateLimitResponse is a mock GitHub rate limit API response.
const GitHubRateLimitResponse = `{
"resources": {
"core": {
"limit": 5000,
"used": 1,
"remaining": 4999,
"reset": 1699027200
},
"search": {
"limit": 30,
"used": 0,
"remaining": 30,
"reset": 1699027200
}
},
"rate": {
"limit": 5000,
"used": 1,
"remaining": 4999,
"reset": 1699027200
}
"resources": {
"core": {
"limit": 5000,
"used": 1,
"remaining": 4999,
"reset": 1699027200
},
"search": {
"limit": 30,
"used": 0,
"remaining": 30,
"reset": 1699027200
}
},
"rate": {
"limit": 5000,
"used": 1,
"remaining": 4999,
"reset": 1699027200
}
}`
// SimpleTemplate is a basic template for testing.
const SimpleTemplate = `# {{ .Name }}
{{ .Description }}
## Installation
` + "```yaml" + `
uses: {{ gitOrg . }}/{{ gitRepo . }}@{{ actionVersion . }}
` + "```" + `
{{ if .Inputs }}
## Inputs
| Name | Description | Required | Default |
|------|-------------|----------|---------|
{{ range $key, $input := .Inputs -}}
| ` + "`{{ $key }}`" + ` | {{ $input.Description }} | {{ $input.Required }} | {{ $input.Default }} |
{{ end -}}
{{ end }}
{{ if .Outputs }}
## Outputs
| Name | Description |
|------|-------------|
{{ range $key, $output := .Outputs -}}
| ` + "`{{ $key }}`" + ` | {{ $output.Description }} |
{{ end -}}
{{ end }}
`
// GitHubErrorResponse is a mock GitHub error API response.
const GitHubErrorResponse = `{
"message": "Not Found",
"documentation_url": "https://docs.github.com/rest"
"message": "Not Found",
"documentation_url": "https://docs.github.com/rest"
}`
// MockGitHubResponses returns a map of URL patterns to mock responses.
func MockGitHubResponses() map[string]string {
return map[string]string{
"GET https://api.github.com/repos/actions/checkout/releases/latest": GitHubReleaseResponse,
"GET https://api.github.com/repos/actions/checkout/tags": `[` + GitHubTagResponse + `]`,
"GET https://api.github.com/repos/actions/checkout": GitHubRepoResponse,
"GET https://api.github.com/repos/actions/checkout/git/ref/tags/v4.1.1": `{
"ref": "refs/tags/v4.1.1",
"node_id": "REF_kwDOAJy2KM9yZXJlZnMvdGFncy92NC4xLjE",
"url": "https://api.github.com/repos/actions/checkout/git/refs/tags/v4.1.1",
"object": {
"sha": "8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e",
"type": "commit",
"url": "https://api.github.com/repos/actions/checkout/git/commits/8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e"
}
}`,
"GET https://api.github.com/repos/actions/checkout/tags": `[` + GitHubTagResponse + `]`,
"GET https://api.github.com/repos/actions/checkout": GitHubRepoResponse,
"GET https://api.github.com/repos/actions/checkout/commits/" +
"8f4b7f84bd579b95d7f0b90f8d8b6e5d9b8a7f6e": GitHubCommitResponse,
"GET https://api.github.com/rate_limit": GitHubRateLimitResponse,
"GET https://api.github.com/repos/actions/setup-node/releases/latest": `{
"id": 123457,
"tag_name": "v4.0.0",
"name": "v4.0.0",
"body": "## What's Changed\n* Update Node.js versions\n* Fix compatibility issues",
"draft": false,
"prerelease": false,
"created_at": "2023-10-15T10:00:00Z",
"published_at": "2023-10-15T10:00:00Z"
"id": 123457,
"tag_name": "v4.0.0",
"name": "v4.0.0",
"body": "## What's Changed\n* Update Node.js versions\n* Fix compatibility issues",
"draft": false,
"prerelease": false,
"created_at": "2023-10-15T10:00:00Z",
"published_at": "2023-10-15T10:00:00Z"
}`,
"GET https://api.github.com/repos/actions/setup-node/git/ref/tags/v4.0.0": `{
"ref": "refs/tags/v4.0.0",
"node_id": "REF_kwDOAJy2KM9yZXJlZnMvdGFncy92NC4wLjA",
"url": "https://api.github.com/repos/actions/setup-node/git/refs/tags/v4.0.0",
"object": {
"sha": "1a4e6d7c9f8e5b2a3c4d5e6f7a8b9c0d1e2f3a4b",
"type": "commit",
"url": "https://api.github.com/repos/actions/setup-node/git/commits/1a4e6d7c9f8e5b2a3c4d5e6f7a8b9c0d1e2f3a4b"
}
}`,
"GET https://api.github.com/repos/actions/setup-node/tags": `[{
"name": "v4.0.0",
"commit": {
"sha": "1a4e6d7c9f8e5b2a3c4d5e6f7a8b9c0d1e2f3a4b",
"url": "https://api.github.com/repos/actions/setup-node/commits/1a4e6d7c9f8e5b2a3c4d5e6f7a8b9c0d1e2f3a4b"
}
"name": "v4.0.0",
"commit": {
"sha": "1a4e6d7c9f8e5b2a3c4d5e6f7a8b9c0d1e2f3a4b",
"url": "https://api.github.com/repos/actions/setup-node/commits/1a4e6d7c9f8e5b2a3c4d5e6f7a8b9c0d1e2f3a4b"
}
}]`,
}
}

View File

@@ -192,6 +192,30 @@ branding:
`, name, description, inputsYAML.String())
}
// SetupTestTemplates creates template files for testing.
func SetupTestTemplates(t *testing.T, dir string) {
t.Helper()
// Create templates directory structure
templatesDir := filepath.Join(dir, "templates")
themesDir := filepath.Join(templatesDir, "themes")
// Create directories
for _, theme := range []string{"github", "gitlab", "minimal", "professional"} {
themeDir := filepath.Join(themesDir, theme)
if err := os.MkdirAll(themeDir, 0755); err != nil {
t.Fatalf("failed to create theme dir %s: %v", themeDir, err)
}
// Write theme template
templatePath := filepath.Join(themeDir, "readme.tmpl")
WriteTestFile(t, templatePath, SimpleTemplate)
}
// Create default template
defaultTemplatePath := filepath.Join(templatesDir, "readme.tmpl")
WriteTestFile(t, defaultTemplatePath, SimpleTemplate)
}
// CreateCompositeAction creates a test composite action with dependencies.
func CreateCompositeAction(name, description string, steps []string) string {
var stepsYAML bytes.Buffer