-
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
Merged
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
7acb558
ci(tests): run go test on windows-latest alongside ubuntu
lexfrei 037499a
build(release): package windows binaries as zip
lexfrei ff4df6f
feat(secureperm): add cross-platform sensitive-file helper
lexfrei c67a32c
refactor(security): route sensitive writes through secureperm
lexfrei 8c1d621
test(commands): cover backslash template paths on windows
lexfrei 8e220ee
fix(kubeconfig): remove vacuous 'if err == nil' wrapper
lexfrei 8b168fa
refactor(init): add writeSecureToDestination for secrets
lexfrei 6935f77
test(commands): make windows path test drive-independent
lexfrei 8df7209
test(secureperm): assert windows DACL is protected and owner-only
lexfrei 3c20d27
docs(readme): document windows support
lexfrei 5976347
fix(secureperm): downgrade mode when overwriting existing lax file
lexfrei e97ae14
fix(secureperm): create windows files with protected DACL from the start
lexfrei 1f15b91
fix(init): don't print 'Created' when the write failed
lexfrei 43b7939
fix(secureperm): tighten DACL on overwrite of existing windows file
lexfrei ba45c9c
test(init): use filepath.Join for OS-portable path assertion
lexfrei 9cb3adb
fix(secureperm): atomic write via tmp + rename preserves original on …
lexfrei f84e129
fix(template): route --inplace write through secureperm
lexfrei 59dfc5c
docs(secureperm): rewrite package doc to match atomic write strategy
lexfrei 4b7fe08
test(secureperm): preserve-original-on-failure test for windows
lexfrei 7b6a9c8
refactor(init): drop redundant validateFileExists from writeSecretsBu…
lexfrei 3a95079
docs(test): reword apply_windows_test comment per project convention
lexfrei 22d2ce3
test(template): cover backslash -t input on windows end-to-end
lexfrei 45a455c
test(age): pin talm.key mode 0600 on unix
lexfrei 6b1d1f1
docs(readme): narrow windows path-separator claim to -t/--template
lexfrei c2d4469
fix(tests): adapt tests for windows CI runner
lexfrei 9554f92
fix(commands): tighten outside-root path check to match path element
lexfrei eb55b62
fix(init): create secrets parent dir with 0o700
lexfrei 54694fb
fix(secureperm): fsync tmp file and parent dir on unix
lexfrei 7565632
test(template): force seed mode independent of umask
lexfrei 9c4d746
test(secureperm): force seed mode independent of umask
lexfrei 7187260
test(commands): pin isOutsideRoot contract directly
lexfrei 570171f
fix(kubeconfig): use isOutsideRoot helper for path classification
lexfrei e595a1b
fix(secureperm): fsync tmp before rename on Windows
lexfrei ce4b9fa
docs(secureperm): note owner-change side-effect of tmp+rename
lexfrei f5b584b
docs(test): warn that os.Chdir tests are not t.Parallel-safe
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
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]) | ||
| } | ||
| } |
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.
fail-fast: falseis correct, just confirming intentReads as "let both runners finish even if one fails." That's the right call for a platform-parity matrix — you want to see Windows-specific failures even if Linux passed (or vice versa). Just calling it out so the PR description's "watch for
--- PASSon both runners" claim is verified by behavior, not just name.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.
Confirmed —
fail-fast: falseis intentional precisely so a Windows-specific failure surfaces even when Linux is green (and vice versa). I'll make the behavioural claim explicit in future PR descriptions rather than letting it ride on the reader recognising the strategy block.