diff --git a/pkg/security/risks/builtin/unencrypted_asset_rule_test.go b/pkg/security/risks/builtin/unencrypted_asset_rule_test.go new file mode 100644 index 00000000..918211de --- /dev/null +++ b/pkg/security/risks/builtin/unencrypted_asset_rule_test.go @@ -0,0 +1,236 @@ +package builtin + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/threagile/threagile/pkg/security/types" +) + +func TestUnencryptedAssetRuleGenerateRisksEmptyModelNotRisksCreated(t *testing.T) { + rule := NewUnencryptedAssetRule() + + risks, err := rule.GenerateRisks(&types.Model{}) + + assert.Nil(t, err) + assert.Empty(t, risks) +} + +type UnencryptedAssetRuleTest struct { + isEmbeddedComponent bool + isNoStorageAtRest bool + isUsuallyStoringEndUserData bool + storedAnyData bool + outOfScope bool + encryption types.EncryptionStyle + dataConfidentiality types.Confidentiality + dataIntegrity types.Criticality + + riskCreated bool + expectedImpact types.RiskExploitationImpact + expectedSuffixTitle string +} + +func TestUnencryptedAssetRuleGenerateRisks(t *testing.T) { + testCases := map[string]UnencryptedAssetRuleTest{ + "out of scope": { + outOfScope: true, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + storedAnyData: true, + dataConfidentiality: types.StrictlyConfidential, + dataIntegrity: types.MissionCritical, + + riskCreated: false, + }, + "encryption waiver because no storage at rest": { + outOfScope: false, + isNoStorageAtRest: true, + isEmbeddedComponent: false, + storedAnyData: true, + dataConfidentiality: types.StrictlyConfidential, + dataIntegrity: types.MissionCritical, + + riskCreated: false, + }, + "encryption waiver because embedded component": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: true, + storedAnyData: true, + dataConfidentiality: types.StrictlyConfidential, + dataIntegrity: types.MissionCritical, + + riskCreated: false, + }, + "do not store any data": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + storedAnyData: false, + dataConfidentiality: types.StrictlyConfidential, + dataIntegrity: types.MissionCritical, + + riskCreated: false, + }, + "confidentiality restricted and integrity operational": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + storedAnyData: true, + dataConfidentiality: types.Restricted, + dataIntegrity: types.Operational, + + riskCreated: false, + }, + "encrypted not very sensitive": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + storedAnyData: true, + dataConfidentiality: types.Confidential, + dataIntegrity: types.Critical, + encryption: types.Transparent, + + riskCreated: false, + }, + "very sensitive end user individual Key": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + storedAnyData: true, + dataConfidentiality: types.StrictlyConfidential, + dataIntegrity: types.MissionCritical, + encryption: types.DataWithEndUserIndividualKey, + + riskCreated: false, + }, + "not very sensitive no encryption": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + storedAnyData: true, + dataConfidentiality: types.Confidential, + dataIntegrity: types.Critical, + encryption: types.NoneEncryption, + + riskCreated: true, + expectedImpact: types.MediumImpact, + }, + "very sensitive strictly confidential no encryption": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + storedAnyData: true, + dataConfidentiality: types.StrictlyConfidential, + dataIntegrity: types.Critical, + encryption: types.NoneEncryption, + + riskCreated: true, + expectedImpact: types.HighImpact, + }, + "very sensitive mission critical no encryption": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + storedAnyData: true, + dataConfidentiality: types.Confidential, + dataIntegrity: types.MissionCritical, + encryption: types.NoneEncryption, + + riskCreated: true, + expectedImpact: types.HighImpact, + }, + "very sensitive transparent encryption": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + isUsuallyStoringEndUserData: true, + storedAnyData: true, + dataConfidentiality: types.StrictlyConfidential, + dataIntegrity: types.MissionCritical, + encryption: types.Transparent, + + riskCreated: true, + expectedImpact: types.MediumImpact, + expectedSuffixTitle: " missing end user individual encryption with data-with-end-user-individual-key", + }, + "very sensitive DataWithSymmetricSharedKey encryption": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + isUsuallyStoringEndUserData: true, + storedAnyData: true, + dataConfidentiality: types.StrictlyConfidential, + dataIntegrity: types.MissionCritical, + encryption: types.DataWithSymmetricSharedKey, + + riskCreated: true, + expectedImpact: types.MediumImpact, + expectedSuffixTitle: " missing end user individual encryption with data-with-end-user-individual-key", + }, + "very sensitive DataWithAsymmetricSharedKey encryption": { + outOfScope: false, + isNoStorageAtRest: false, + isEmbeddedComponent: false, + isUsuallyStoringEndUserData: true, + storedAnyData: true, + dataConfidentiality: types.StrictlyConfidential, + dataIntegrity: types.MissionCritical, + encryption: types.DataWithAsymmetricSharedKey, + + riskCreated: true, + expectedImpact: types.MediumImpact, + expectedSuffixTitle: " missing end user individual encryption with data-with-end-user-individual-key", + }, + } + + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + rule := NewUnencryptedAssetRule() + dataAssetsStore := []string{} + if testCase.storedAnyData { + dataAssetsStore = append(dataAssetsStore, "da1") + } + risks, err := rule.GenerateRisks(&types.Model{ + TechnicalAssets: map[string]*types.TechnicalAsset{ + "ta1": { + Title: "Test Technical Asset", + OutOfScope: testCase.outOfScope, + Technologies: types.TechnologyList{ + { + Name: "service-registry", + Attributes: map[string]bool{ + types.IsEmbeddedComponent: testCase.isEmbeddedComponent, + types.IsNoStorageAtRest: testCase.isNoStorageAtRest, + types.IsUsuallyStoringEndUserData: testCase.isUsuallyStoringEndUserData, + }, + }, + }, + DataAssetsStored: dataAssetsStore, + Encryption: testCase.encryption, + }, + }, + DataAssets: map[string]*types.DataAsset{ + "da1": { + Title: "Test Data Asset", + Confidentiality: testCase.dataConfidentiality, + Integrity: testCase.dataIntegrity, + }, + }, + }) + + assert.Nil(t, err) + if testCase.riskCreated { + assert.NotEmpty(t, risks) + assert.Equal(t, testCase.expectedImpact, risks[0].ExploitationImpact) + expectedMessage := fmt.Sprintf("Unencrypted Technical Asset named Test Technical Asset%s", testCase.expectedSuffixTitle) + assert.Equal(t, risks[0].Title, expectedMessage) + } else { + assert.Empty(t, risks) + } + }) + } + +}