-
Notifications
You must be signed in to change notification settings - Fork 23
fix(windows): CI matrix, zip archives, and NTFS ACL for sensitive files #129
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
Open
lexfrei
wants to merge
25
commits into
main
Choose a base branch
from
fix/windows-support
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
3047443
ci(tests): run go test on windows-latest alongside ubuntu
lexfrei ba12fe9
build(release): package windows binaries as zip
lexfrei 791556f
feat(secureperm): add cross-platform sensitive-file helper
lexfrei aecd9de
refactor(security): route sensitive writes through secureperm
lexfrei 83a30a6
test(commands): cover backslash template paths on windows
lexfrei e739fea
fix(kubeconfig): remove vacuous 'if err == nil' wrapper
lexfrei a2d649b
refactor(init): add writeSecureToDestination for secrets
lexfrei a67fd39
test(commands): make windows path test drive-independent
lexfrei 1d8c122
test(secureperm): assert windows DACL is protected and owner-only
lexfrei 3052812
docs(readme): document windows support
lexfrei d39564b
fix(secureperm): downgrade mode when overwriting existing lax file
lexfrei bcdc03e
fix(secureperm): create windows files with protected DACL from the start
lexfrei 0d56640
fix(init): don't print 'Created' when the write failed
lexfrei dd7fafc
fix(secureperm): tighten DACL on overwrite of existing windows file
lexfrei 22acf5c
test(init): use filepath.Join for OS-portable path assertion
lexfrei 1242217
fix(secureperm): atomic write via tmp + rename preserves original on …
lexfrei 74f7c94
fix(template): route --inplace write through secureperm
lexfrei fe20b3c
docs(secureperm): rewrite package doc to match atomic write strategy
lexfrei c0f3ac4
test(secureperm): preserve-original-on-failure test for windows
lexfrei 2b34d06
refactor(init): drop redundant validateFileExists from writeSecretsBu…
lexfrei e6244cd
docs(test): reword apply_windows_test comment per project convention
lexfrei fcddba7
test(template): cover backslash -t input on windows end-to-end
lexfrei 6d39264
test(age): pin talm.key mode 0600 on unix
lexfrei 8d4d0a0
docs(readme): narrow windows path-separator claim to -t/--template
lexfrei 855b13b
fix(tests): adapt tests for windows CI runner
lexfrei File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| //go:build !windows | ||
|
|
||
| // Copyright Cozystack Authors | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package age_test | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "testing" | ||
|
|
||
| "github.com/cozystack/talm/pkg/age" | ||
| ) | ||
|
|
||
| // TestGenerateKey_Mode0600_Unix pins that the age private key file | ||
| // is written with owner-only permissions. The file contains the raw | ||
| // X25519 private key that protects every encrypted secret in the | ||
| // project — if a future refactor ever swaps secureperm.WriteFile | ||
| // back to os.WriteFile with a different mode, this test fails. | ||
| func TestGenerateKey_Mode0600_Unix(t *testing.T) { | ||
| dir := t.TempDir() | ||
|
|
||
| identity, created, err := age.GenerateKey(dir) | ||
| if err != nil { | ||
| t.Fatalf("GenerateKey: %v", err) | ||
| } | ||
| if !created { | ||
| t.Fatal("expected GenerateKey to create a new key in an empty dir") | ||
| } | ||
| if identity == nil { | ||
| t.Fatal("nil identity from GenerateKey") | ||
| } | ||
|
|
||
| keyPath := filepath.Join(dir, "talm.key") | ||
| info, err := os.Stat(keyPath) | ||
| if err != nil { | ||
| t.Fatalf("Stat: %v", err) | ||
| } | ||
| if got := info.Mode().Perm(); got != 0o600 { | ||
| t.Errorf("talm.key mode = %o, want 0600", got) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| //go:build windows | ||
|
|
||
| // Copyright Cozystack Authors | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package commands | ||
|
|
||
| import ( | ||
| "path/filepath" | ||
| "strings" | ||
| "testing" | ||
| ) | ||
|
|
||
| // TestResolveTemplatePaths_BackslashInput pins that users running | ||
| // `talm apply` from PowerShell with template arguments that use | ||
| // backslash separators (e.g. "templates\worker.yaml") end up with | ||
| // forward-slash paths. The downstream helm engine only looks up | ||
| // templates by forward-slash map keys, so anything else fails with | ||
| // "template not found". | ||
| func TestResolveTemplatePaths_BackslashInput(t *testing.T) { | ||
| rootDir := t.TempDir() | ||
| absRoot, err := filepath.Abs(rootDir) | ||
| if err != nil { | ||
| t.Fatalf("abs root: %v", err) | ||
| } | ||
|
|
||
| tests := []struct { | ||
| name string | ||
| input string | ||
| want string | ||
| }{ | ||
| { | ||
| name: "relative with backslash", | ||
| input: `templates\controlplane.yaml`, | ||
| want: "templates/controlplane.yaml", | ||
| }, | ||
| { | ||
| name: "relative nested backslashes", | ||
| input: `templates\nested\worker.yaml`, | ||
| want: "templates/nested/worker.yaml", | ||
| }, | ||
| { | ||
| name: "mixed separators", | ||
| input: `templates\nested/worker.yaml`, | ||
| want: "templates/nested/worker.yaml", | ||
| }, | ||
| { | ||
| name: "absolute path inside root", | ||
| input: filepath.Join(absRoot, "templates", "controlplane.yaml"), | ||
| want: "templates/controlplane.yaml", | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| got := resolveTemplatePaths([]string{tt.input}, rootDir) | ||
| if len(got) != 1 { | ||
| t.Fatalf("expected 1 result, got %d", len(got)) | ||
| } | ||
| if got[0] != tt.want { | ||
| t.Errorf("resolveTemplatePaths(%q) = %q, want %q", tt.input, got[0], tt.want) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| // TestResolveTemplatePaths_OutsideRoot_Backslash asserts that a | ||
| // backslash path resolving outside rootDir still emerges without any | ||
| // backslashes — the helm engine only looks up templates by forward- | ||
| // slash map keys, so regardless of which internal branch the function | ||
| // takes (Rel-success, Rel-failure, prefix-checks), the result must be | ||
| // backslash-free. Constructing `outside` via filepath.Join on rootDir | ||
| // keeps the test on the same drive as t.TempDir() and works on any | ||
| // GitHub Actions runner image. | ||
| func TestResolveTemplatePaths_OutsideRoot_Backslash(t *testing.T) { | ||
| rootDir := t.TempDir() | ||
| outside := filepath.Join(rootDir, "..", "..", "..", "elsewhere", "templates", "foo.yaml") | ||
|
|
||
| got := resolveTemplatePaths([]string{outside}, rootDir) | ||
| if len(got) != 1 { | ||
| t.Fatalf("expected 1 result, got %d", len(got)) | ||
| } | ||
| if strings.ContainsRune(got[0], '\\') { | ||
| t.Errorf("result still contains backslash: %q", got[0]) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since
writeSecureToDestinationis specifically designed for sensitive files (liketalm.keyandsecrets.yaml), the parent directory should be created with restrictive permissions (0700) on Unix-like systems. Usingos.ModePerm(0777) relies entirely on the system umask and may leave the directory world-readable or world-writable in some environments, which is inconsistent with the goal of this security-focused helper.