-
Notifications
You must be signed in to change notification settings - Fork 14
Dev/anasanc/pep addingcommonextensioncode #41
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
16 commits
Select commit
Hold shift + click to select a range
0f081ef
introduced extension policy file to lib
alsanmsft ff00ec8
initial commit for common code
alsanmsft ac4d421
added UTs and cleaned up code for allowlist validation
alsanmsft db0e087
adding new linux and windows files
alsanmsft 16d4915
WIP
alsanmsft 96e5f13
nit change
alsanmsft 336d3e5
adding nil check for filepath
alsanmsft 160ebdf
commenting out error line
alsanmsft 0cf99cd
nit
alsanmsft 14a903b
nit
alsanmsft 17aecba
removing logging rn for testing purposes
alsanmsft a56cc80
beginning to clean up
alsanmsft 4828fb3
library code for compute hash, allowlist validation, loading policy s…
alsanmsft d471ed6
del later files
alsanmsft d83d87b
adding UTs + case insensitive search
alsanmsft 25c233b
del personal comment
alsanmsft 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| package extensionpolicysettings | ||
|
|
||
| import ( | ||
| "crypto/sha1" | ||
| "crypto/sha256" | ||
| "encoding/hex" | ||
| "encoding/json" | ||
| "fmt" | ||
| "os" | ||
| "strings" | ||
|
|
||
| "github.com/Azure/azure-extension-platform/pkg/extensionerrors" | ||
| ) | ||
|
|
||
| type ExtensionPolicySettings interface { | ||
| ValidateFormat() error | ||
| } | ||
|
|
||
| type ExtensionPolicySettingsManager[T ExtensionPolicySettings] struct { | ||
| settingsFilePath string | ||
| settings *T | ||
| } | ||
|
|
||
| func NewExtensionPolicySettingsManager[T ExtensionPolicySettings](policyFilePath string) (*ExtensionPolicySettingsManager[T], error) { | ||
| if policyFilePath == "" { | ||
| return nil, extensionerrors.ErrEmptyPolicyFilePath | ||
| } | ||
| return &ExtensionPolicySettingsManager[T]{ | ||
| settingsFilePath: policyFilePath, | ||
| }, nil | ||
| } | ||
|
|
||
| func (epsm *ExtensionPolicySettingsManager[T]) LoadExtensionPolicySettings() error { | ||
| if epsm == nil { | ||
| return fmt.Errorf("invalid ExtensionPolicySettingsManager: manager is nil") | ||
| } | ||
| if epsm.settingsFilePath == "" { | ||
| return extensionerrors.ErrEmptyPolicyFilePath | ||
| } | ||
|
|
||
| // If an extension has a default policy configuration in case the file does not exist, they should handle that logic before calling this function. | ||
| if _, err := os.Stat(epsm.settingsFilePath); os.IsNotExist(err) { | ||
| return extensionerrors.ErrMissingPolicyFile | ||
| } else if err != nil { | ||
| return fmt.Errorf("error checking extension policy settings file: %w", err) | ||
| } | ||
|
|
||
| fileContent, err := os.ReadFile(epsm.settingsFilePath) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to read extension policy settings file: %w", err) // TODO: Add retry logic if appropriate. | ||
| } | ||
|
|
||
| if len(fileContent) == 0 { | ||
| return extensionerrors.ErrEmptyPolicyFile | ||
| } | ||
|
|
||
| var settings *T = new(T) | ||
| if err := json.Unmarshal(fileContent, settings); err != nil { | ||
| return fmt.Errorf("failed to unmarshal extension policy settings: %w", err) | ||
| } | ||
|
|
||
| // Extensions themselves must decide the criteria for valid policy settings (i.e., if they can be null etc.). | ||
| if err := (*settings).ValidateFormat(); err != nil { | ||
| return fmt.Errorf("extension policy loaded, but invalid format: %w", err) | ||
| } | ||
|
|
||
| epsm.settings = settings | ||
| return nil | ||
| } | ||
|
|
||
| func (epsm *ExtensionPolicySettingsManager[T]) GetSettings() (*T, error) { | ||
| if epsm.settings == nil { | ||
| return nil, extensionerrors.ErrPolicyNotYetLoaded | ||
| } | ||
| return epsm.settings, nil | ||
| } | ||
|
|
||
| // Validation Helper Functions | ||
| type HashType int | ||
|
|
||
| const ( | ||
| HashTypeNone HashType = iota | ||
| HashTypeSHA1 | ||
| HashTypeSHA256 | ||
| ) | ||
|
|
||
| func ValidateValueInAllowlist(value string, allowlist []string) error { | ||
| if len(allowlist) == 0 { | ||
| return extensionerrors.ErrPolicyAllowlistEmpty | ||
| } | ||
|
|
||
| for _, allowlistValue := range allowlist { | ||
| // Although a hash value wouldn't have whitespace we trim spaces for other use cases of this function. | ||
| trimmedAllowlistValue := strings.TrimSpace(allowlistValue) | ||
| trimmedValue := strings.TrimSpace(value) | ||
| if strings.EqualFold(trimmedValue, trimmedAllowlistValue) { | ||
| return nil | ||
| } | ||
| } | ||
| return extensionerrors.ErrItemNotInAllowlist | ||
| } | ||
|
|
||
| // This function is the entry point for most use cases: it takes in the filepath, reads the content, and | ||
| // determines if the content is allowlisted. If hashOpt is not HashTypeNone, it will compute the hash of the file content. | ||
| // If extensions don't want to validate a filepath but a value directly, they can call ValidateValueInAllowlist, | ||
| // which this function calls. | ||
| func ValidateFileHashInAllowlist(filePath string, allowlist []string, hashOpt HashType) error { | ||
| if len(allowlist) == 0 { | ||
| return extensionerrors.ErrPolicyAllowlistEmpty | ||
| } | ||
|
|
||
| if filePath == "" { | ||
| return extensionerrors.ErrEmptyFilepathToValidate | ||
| } | ||
|
|
||
| if _, err := os.Stat(filePath); os.IsNotExist(err) { | ||
| return fmt.Errorf("file to validate does not exist: %w", err) | ||
| } | ||
|
|
||
| content, err := os.ReadFile(filePath) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to read file %s for validation: %w", filePath, err) | ||
| } | ||
|
|
||
| value := string(content) | ||
|
|
||
| if hashOpt != HashTypeNone { | ||
| value, err := ComputeFileHash(value, hashOpt) | ||
| if err != nil { | ||
| return fmt.Errorf("error occured when hashing contents of file %s for validation: %w", filePath, err) | ||
| } | ||
| return ValidateValueInAllowlist(value, allowlist) | ||
| } | ||
|
|
||
| return ValidateValueInAllowlist(value, allowlist) | ||
| } | ||
|
|
||
| // ComputeFileHash computes the hash of a file or leaves string as is. | ||
| func ComputeFileHash(contents string, hashOpt HashType) (string, error) { | ||
| var hashStr string | ||
| switch hashOpt { | ||
| case HashTypeSHA1: | ||
| hash := sha1.Sum([]byte(contents)) | ||
| hashStr = hex.EncodeToString(hash[:]) | ||
| default: | ||
| hash := sha256.Sum256([]byte(contents)) | ||
| hashStr = hex.EncodeToString(hash[:]) | ||
| } | ||
|
|
||
| return hashStr, nil | ||
| } | ||
Oops, something went wrong.
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.
What I'm wondering is whether the search should be done case insensitive. That seems to make sense to me.
Also not a bad idea to trim the values.