Compare commits

...

8 Commits

Author SHA1 Message Date
Rodolfo Campos ecc021985e
Merge pull request #109 from camposer/fix/serve-handle-file-error
Fix/serve handle file error
2021-10-14 16:08:27 +02:00
Rodolfo Campos f64aed0f60 Improve mockConfig (#48) 2021-10-14 16:06:46 +02:00
wallrony 76fb5ec31a Add tests to procedures, policies and standards (#48) 2021-10-13 15:04:20 -03:00
Rodolfo Campos ad2c89ec67 Check generated documents in tests (#48) 2021-10-12 14:46:30 +02:00
Rodolfo Campos 1c80e1ce66 Add tests (#48) 2021-10-12 12:14:30 +02:00
wallrony 53a65f6c00 Add handling errors in read policies and narratives (#48) 2021-10-08 10:45:41 -03:00
wallrony 373e7737ab Change loadMDMD method to return the error (#48) 2021-10-08 10:43:08 -03:00
wallrony ac11b307ec Add error handling in .dm file structure (#48) 2021-10-07 15:23:23 -03:00
9 changed files with 725 additions and 20 deletions

View File

@ -0,0 +1,94 @@
name: Control Environment Narrative
acronym: CEN
satisfies:
TSC:
- CC2.1
- CC2.2
- CC2.3
- CC4.1
- CC4.2
- CC5.1
- CC5.2
- CC5.3
majorRevisions:
- date: Jun 1 2018
comment: Initial document
---
# Control Environment Narrative
The following provides a description of the control structure of {{.Name}}.
The intent of this description is to enumerate the logical, policy, and procedural controls that serve to monitor {{.Name}}'s application and data security. Changes uncovered by these procedures in the logical, policy, procedural, or customer environment are addressed by remediations specific to the noted change.
# Logical Controls
{{.Name}} employs several logical controls to protect confidential data and ensure normal operation of its core product.
- Mandatory data encryption at rest and in motion
- Multi-factor authentication for access to cloud infrastructure
- Activity and anomaly monitoring on production systems
- Vulnerability management program
# Policy Controls
{{.Name}} employs several policy controls to protect confidential data and ensure normal operation of its core product. These policies include, but are not limited to:
- Access Control Policy
- Encryption Policy
- Office Security Policy
- Password Policy
- Policy Training Policy
- Vendor Policy
- Workstation Policy
# Procedural Controls
{{.Name}} has numerous scheduled procedures to monitor and tune the effectiveness of ongoing security controls, and a series of event-driven procedures to respond to security-related events.
TODO: Finalize these lists
## Scheduled Security and Audit Procedures
- Review Access [quarterly]
- Review Security Logs [weekly]
- Review Cyber Risk Assessment (enumerate possible compromise scenarios) [quarterly]
- Review Data Classification [quarterly]
- Backup Testing [quarterly]
- Disaster Recovery Testing [semi-annual]
- Review Devices & Workstations [quarterly]
- Review & Clear Low-Priority Alerts [weekly]
- Apply OS Patches [monthly]
- Verify Data Disposal per Retention Policy [quarterly]
- Conduct Security Training [annual]
- Review Security Monitoring and Alerting Configuration [quarterly]
- Penetration Test [annual]
- Whitebox Security Review [annual]
- SOC2 Audit [annual]
## Event-Driven Security and Audit Procedures
- Onboard Employee
- Offboard Employee
- Investigate Security Alert
- Investigate Security Incident
# Remediations
{{.Name}} uses the outcomes of the aforementioned controls and procedures to identify shortcomings in the existing control environment. Once identified, these shortcomes are remediated by improving existing controls and procedures, and creating new controls and procedures as needed.
# Communications
{{.Name}} communicates relevant information regarding the functioning of the above controls with internal and external parties on an as-needed basis and according to statutory requirements.
## Internal
{{.Name}} communicates control outcomes, anomalies, and remediations internally using the following channels:
- Slack
- Email
- Github ticketing
## External
{{.Name}} communicates relevant control-related information to external parties including shareholders, customers, contractors, regulators, and government entities as needed according to contractual and regulatory/statutory obligation.

View File

@ -0,0 +1,57 @@
name: Access Onboarding and Termination Policy
acronym: AOTP
satisfies:
TSC:
- CC6.1
- CC6.2
- CC6.3
majorRevisions:
- date: Jun 1 2018
comment: Initial document
---
# Purpose and Scope
a. The purpose of this policy is to define procedures to onboard and offboard users to technical infrastructure in a manner that minimizes the risk of information loss or exposure.
a. This policy applies to all technical infrastructure within the organization.
a. This policy applies to all full-time and part-time employees and contractors.
# Background
a. In order to minimize the risk of information loss or exposure (from both inside and outside the organization), the organization is reliant on the principle of least privilege. Account creation and permission levels are restricted to only the resources absolutely needed to perform each persons job duties. When a users role within the organization changes, those accounts and permission levels are changed/revoked to fit the new role and disabled when the user leaves the organization altogether.
# Policy
a. *During onboarding:*
i. Hiring Manager informs HR upon hire of a new employee.
i. HR emails IT to inform them of a new hire and their role.
i. IT creates a checklist of accounts and permission levels needed for that role.
i. The owner of each resource reviews and approves account creation and the
associated permissions.
i. IT works with the owner of each resource to set up the user.
a. *During offboarding:*
i. Hiring Manager notifies HR when an employee has been terminated.
i. HR sends a weekly email report to IT summarizing list of users terminated and instructs IT to disable their access.
i. IT terminates access within five business days from receipt of notification.
a. *When an employee changes roles within the organization:*
i. Hiring Manager will inform HR of a change in role.
i. HR and IT will follow the same steps as outlined in the onboarding and offboarding procedures.
a. *Review of accounts and permissions:*
i. Each month, IT and HR will review accounts and permission levels for accuracy.

View File

@ -0,0 +1,39 @@
id: "workstation"
name: "Collect Workstation Details"cron: "0 0 0 15 4 *"
---
Resolve this ticket by executing the following steps:
- [ ] Send the communications below
- [ ] For any email replies, attach content to this ticket
- [ ] Validate responses are received from each
```
To: Desktop support
Subject: Annual workstation inventory
Please attach the current workstation inventory to the following ticket: [REPLACE WITH URL TO THIS TICKET]
The workstation inventory shall include the following fields:
* Serial number
* Custodian
* Full disk encryption status
* Malware protection status
```
```
To: Outsourced Call Center IT
Subject: Annual workstation inventory
As part of our ongoing compliance efforts and per our services agreement, we require a current inventory of workstations in use in the service of our account.
Please respond to this message with the current inventory.
The workstation inventory shall include the following fields:
* Serial number
* Custodian
* Full disk encryption status
* Malware protection status
```

View File

@ -0,0 +1,245 @@
name: TSC
***CC1.1:
family: CC1
name: Integrity and Ethics
description: The entity demonstrates a commitment to integrity and ethical values
CC1.2:
family: CC1
name: Board Independence
description: The board of directors demonstrates independence from management and exercises oversight of the development and performance of internal control
CC1.3:
family: CC1
name: Organizational Structure
description: Management establishes, with board oversight, structures, reporting lines, and appropriate authorities and responsibilities in the pursuit of objectives
CC1.4:
family: CC1
name: Hiring, Training and Retention
description: The entity demonstrates a commitment to attract, develop, and retain competent individuals in alignment with objectives
CC1.5:
family: CC1
name: Individual Accountability
description: The entity holds individuals accountable for their internal control responsibilities in the pursuit of objectives.
CC2.1:
family: CC2
name: Use of Information Systems
description: The entity obtains or generates and uses relevant, quality information to support the functioning of internal control
CC2.2:
family: CC2
name: Use of Communication Systems, Internal
description: The entity internally communicates information, including objectives and responsibilities for internal control, necessary to support the functioning of internal control
CC2.3:
family: CC2
name: Use of Communication Systems, External
description: The entity communicates with external parties regarding matters affecting the functioning of internal control
CC3.1:
family: CC3
name: Objectives
description: The entity specifies objectives with sufficient clarity to enable the identification and assessment of risks relating to objectives
CC3.2:
family: CC3
name: Risk to Objectives
description: The entity identifies risks to the achievement of its objectives across the entity and analyzes risks as a basis for determining how the risks should be managed
CC3.3:
family: CC3
name: Fraud Risk to Objectives
description: The entity considers the potential for fraud in assessing risks to the achievement of objectives
CC3.4:
family: CC3
name: Impact of Changes
description: The entity identifies and assesses changes that could significantly impact the system of internal control
CC4.1:
family: CC4
name: Monitoring
description: The entity selects, develops, and performs ongoing and/or separate evaluations to ascertain whether the components of internal control are present and functioning
CC4.2:
family: CC4
name: Remediation
description: The entity evaluates and communicates internal control deficiencies in a timely manner to those parties responsible for taking corrective action, including senior management and the board of directors, as appropriate
CC5.1:
family: CC5
name: Objective Risk Mitigation
description: The entity selects and develops control activities that contribute to the mitigation of risks to the achievement of objectives to acceptable levels
CC5.2:
family: CC5
name: Technology Controls
description: The entity also selects and develops general control activities over technology to support the achievement of objectives
CC5.3:
family: CC5
name: Established Policies
description: The entity deploys control activities through policies that establish what is expected and in procedures that put policies into action
CC6.1:
family: CC6
name: Logical Access
description: The entity implements logical access security software, infrastructure, and architectures over protected information assets to protect them from security events to meet the entitys objectives
CC6.2:
family: CC6
name: User Access
description: Prior to issuing system credentials and granting system access, the entity registers and authorizes new internal and external users whose access is administered by the entity. For those users whose access is administered by the entity, user system credentials are removed when user access is no longer authorized
CC6.3:
family: CC6
name: Role-Based Access
description: The entity authorizes, modifies, or removes access to data, software, functions, and other protected information assets based on roles, responsibilities, or the system design and changes, giving consideration to the concepts of least privilege and segregation of duties, to meet the entitys objectives
CC6.4:
family: CC6
name: Physical Access
description: The entity restricts physical access to facilities and protected information assets (for example, data center facilities, back-up media storage, and other sensitive locations) to authorized personnel to meet the entitys objectives
CC6.5:
family: CC6
name: Data Disposal
description: The entity discontinues logical and physical protections over physical assets only after the ability to read or recover data and software from those assets has been diminished and is no longer required to meet the entitys objectives
CC6.6:
family: CC6
name: External Threats
description: The entity implements logical access security measures to protect against threats from sources outside its system boundaries
CC6.7:
family: CC6
name: Data Custody and Transmission
description: The entity restricts the transmission, movement, and removal of information to authorized internal and external users and processes, and protects it during transmission, movement, or removal to meet the entitys objectives
CC6.8:
family: CC6
name: Malware Detection
description: The entity implements controls to prevent or detect and act upon the introduction of unauthorized or malicious software to meet the entitys objectives
CC7.1:
family: CC7
name: Vulnerability Detection
description: To meet its objectives, the entity uses detection and monitoring procedures to identify (1) changes to configurations that result in the introduction of new vulnerabilities, and (2) susceptibilities to newly discovered vulnerabilities
CC7.2:
family: CC7
name: Anomaly Detection
description: The entity monitors system components and the operation of those components for anomalies that are indicative of malicious acts, natural disasters, and errors affecting the entitys ability to meet its objectives; anomalies are analyzed to determine whether they represent security events
CC7.3:
family: CC7
name: Security Incident Evaluation
description: The entity evaluates security events to determine whether they could or have resulted in a failure of the entity to meet its objectives (security incidents) and, if so, takes actions to prevent or address such failures
CC7.4:
family: CC7
name: Security Incident Response Plan
description: The entity responds to identified security incidents by executing a defined incident response program to understand, contain, remediate, and communicate security incidents, as appropriate
CC7.5:
family: CC7
name: Security Incident Response Execution
description: The entity identifies, develops, and implements activities to recover from identified security incidents
CC8.1:
family: CC8
name: Change Control
description: The entity authorizes, designs, develops or acquires, configures, documents, tests, approves, and implements changes to infrastructure, data, software, and procedures to meet its objectives
CC9.1:
family: CC9
name: Disruption Risk Mitigation
description: The entity identifies, selects, and develops risk mitigation activities for risks arising from potential business disruptions
CC9.2:
family: CC9
name: Vendor Risk Management
description: The entity assesses and manages risks associated with vendors and business partners
A1.1:
family: A1
name: Capacity Planning
description: The entity maintains, monitors, and evaluates current processing capacity and use of system components (infrastructure, data, and software) to manage capacity demand and to enable the implementation of additional capacity to help meet its objectives
A1.2:
family: A1
name: Backup and Recovery
description: The entity authorizes, designs, develops or acquires, implements, operates, approves, maintains, and monitors environmental protections, software, data back-up processes, and recovery infrastructure to meet its objectives
A1.3:
family: A1
name: Recovery Testing
description: The entity tests recovery plan procedures supporting system recovery to meet its objectives
C1.1:
family: C1
name: Confidential Information Identification
description: The entity identifies and maintains confidential information to meet the entitys objectives related to confidentiality
C1.2:
family: C1
name: Confidential Information Disposal
description: The entity disposes of confidential information to meet the entitys objectives related to confidentiality.
PI1.1:
family: PI1
name: Processing Integrity Monitoring
description: The entity obtains or generates, uses, and communicates relevant, quality information regarding the objectives related to processing, including definitions of data processed and product and service speci cations, to support the use of products and services
PI1.2:
family: PI1
name: Processing Integrity Accuracy
description: The entity implements policies and procedures over system inputs, including controls over completeness and accuracy, to result in products, services, and reporting to meet the entitys objectives
PI1.3:
family: PI1
name: Processing Integrity Operations
description: The entity implements policies and procedures over system processing to result in products, services, and reporting to meet the entitys objectives
PI1.4:
family: PI1
name: Processing Integrity Outputs
description: The entity implements policies and procedures to make available or deliver output completely, accurately, and timely in accordance with specifications to meet the entitys objectives
PI1.5:
family: PI1
name: Processing Integrity Backups
description: The entity implements policies and procedures to store inputs, items in processing, and outputs completely, accurately, and timely in accordance with system specifications to meet the entitys objectives
P1.1:
family: P1
name: Privacy Notification
description: The entity provides notice to data subjects about its privacy practices to meet the entitys objectives related to privacy. The notice is updated and communicated to data subjects in a timely manner for changes to the entitys privacy practices, including changes in the use of personal information, to meet the entitys objectives related to privacy
P2.1:
family: P2
name: Privacy Consent and Choice
description: The entity communicates choices available regarding the collection, use, retention, disclosure, and disposal of personal information to the data subjects and the consequences, if any, of each choice. Explicit consent for the collection, use, retention, disclosure, and disposal of personal information is obtained from data subjects or other authorized persons, if required. Such consent is obtained only for the intended purpose of the information to meet the entitys objectives related to privacy. The entitys basis for determining implicit consent for the collection, use, retention, disclosure, and disposal of personal information is documented
P3.1:
family: P3
name: Personal Information Collection
description: Personal information is collected consistent with the entitys objectives related to privacy
P3.2:
family: P3
name: Explicit Consent
description: For information requiring explicit consent, the entity communicates the need for such consent, as well as the consequences of a failure to provide consent for the request for personal information, and obtains the consent prior to the collection of the information to meet the entitys objectives related to privacy
P4.1:
family: P4
name: Proper Use of Personal Information
description: The entity limits the use of personal information to the purposes identified in the entitys objectives related to privacy
P4.2:
family: P4
name: Personal Information Retention
description: The entity retains personal information consistent with the entitys objectives related to privacy
P4.3:
family: P4
name: Personal Information Disposal
description: The entity securely disposes of personal information to meet the entitys objectives related to privacy
P5.1:
family: P5
name: Data Subject Access
description: The entity grants identified and authenticated data subjects the ability to access their stored personal information for review and, upon request, provides physical or electronic copies of that information to data subjects to meet the entitys objectives related to privacy. If access is denied, data subjects are informed of the denial and reason for such denial, as required, to meet the entitys objectives related to privacy
P5.2:
family: P5
name: Data Subject Amendment
description: The entity corrects, amends, or appends personal information based on information provided by data subjects and communicates such information to third parties, as committed or required, to meet the entitys objectives related to privacy. If a request for correction is denied, data subjects are informed of the denial and reason for such denial to meet the entitys objectives related to privacy
P6.1:
family: P6
name: Consent for Third Party Disclosure
description: The entity discloses personal information to third parties with the explicit consent of data subjects, and such consent is obtained prior to disclosure to meet the entitys objectives related to privacy
P6.2:
family: P6
name: Authorized Disclosures
description: The entity creates and retains a complete, accurate, and timely record of authorized disclosures of personal information to meet the entitys objectives related to privacy
P6.3:
family: P6
name: Unauthorized Disclosures
description: The entity creates and retains a complete, accurate, and timely record of detected or reported unauthorized disclosures (including breaches) of personal information to meet the entitys objectives related to privacy
P6.4:
family: P6
name: Appropriate Third Party Disclosure
description: The entity obtains privacy commitments from vendors and other third parties who have access to personal information to meet the entitys objectives related to privacy. The entity assesses those parties compliance on a periodic and as-needed basis and takes corrective action, if necessary
P6.5:
family: P6
name: Unauthorized Third Party Disclosure
description: The entity obtains commitments from vendors and other third parties with access to personal information to notify the entity in the event of actual or suspected unauthorized disclosures of personal information. Such notifications are reported to appropriate personnel and acted on in accordance with established incident response procedures to meet the entitys objectives related to privacy
P6.6:
family: P6
name: Notification of Unauthorized Third Party Disclosure
description: The entity provides notification of breaches and incidents to affected data subjects, regulators, and others to meet the entitys objectives related to privacy
P6.7:
family: P6
name: Accounting of Personal Information
description: The entity provides data subjects with an accounting of the personal information held and disclosure of the data subjects personal information, upon the data subjects request, to meet the entitys objectives related to privacy
P7.1:
family: P7
name: Accuracy of Personal Information
description: The entity collects and maintains accurate, up-to-date, complete, and relevant personal information to meet the entitys objectives related to privacy
P8.1:
family: P8
name: Personal Information Dispute Resolution
description: The entity implements a process for receiving, addressing, resolving, and communicating the resolution of inquiries, complaints, and disputes from data subjects and others and periodically monitors compliance to meet the entitys objectives related to privacy. Corrections and other necessary actions related to identified deficiencies are made or taken in a timely manner

View File

@ -82,7 +82,7 @@ func Exists() bool {
}
// Config is the parsed contents of ProjectRoot()/config.yml.
func Config() *Project {
var Config = func() *Project {
p := Project{}
cfgBytes, err := ioutil.ReadFile(filepath.Join(ProjectRoot(), "comply.yml"))
if err != nil {

View File

@ -83,7 +83,10 @@ func ReadStandards() ([]*Standard, error) {
return nil, errors.Wrap(err, "unable to read "+f.FullPath)
}
yaml.Unmarshal(sBytes, &s)
err = yaml.Unmarshal(sBytes, &s)
if err != nil {
return nil, errors.Wrap(err, "unable to parse "+f.FullPath)
}
standards = append(standards, s)
}
@ -101,7 +104,10 @@ func ReadNarratives() ([]*Document, error) {
for _, f := range files {
n := &Document{}
mdmd := loadMDMD(f.FullPath)
mdmd, err := loadMDMD(f.FullPath)
if err != nil {
return nil, err
}
err = yaml.Unmarshal([]byte(mdmd.yaml), &n)
if err != nil {
return nil, errors.Wrap(err, "unable to parse "+f.FullPath)
@ -120,13 +126,17 @@ func ReadNarratives() ([]*Document, error) {
func ReadProcedures() ([]*Procedure, error) {
var procedures []*Procedure
files, err := path.Procedures()
if err != nil {
return nil, errors.Wrap(err, "unable to enumerate paths")
}
for _, f := range files {
p := &Procedure{}
mdmd := loadMDMD(f.FullPath)
mdmd, err := loadMDMD(f.FullPath)
if err != nil {
return nil, err
}
err = yaml.Unmarshal([]byte(mdmd.yaml), &p)
if err != nil {
return nil, errors.Wrap(err, "unable to parse "+f.FullPath)
@ -151,7 +161,10 @@ func ReadPolicies() ([]*Document, error) {
for _, f := range files {
p := &Document{}
mdmd := loadMDMD(f.FullPath)
mdmd, err := loadMDMD(f.FullPath)
if err != nil {
return nil, err
}
err = yaml.Unmarshal([]byte(mdmd.yaml), &p)
if err != nil {
return nil, errors.Wrap(err, "unable to parse "+f.FullPath)
@ -171,7 +184,7 @@ type metadataMarkdown struct {
body string
}
func loadMDMD(path string) metadataMarkdown {
func loadMDMD(path string) (*metadataMarkdown, error) {
bytes, err := ioutil.ReadFile(path)
if err != nil {
panic(err)
@ -183,9 +196,9 @@ func loadMDMD(path string) metadataMarkdown {
components = components[1:]
}
if len(components) == 1 {
panic(fmt.Sprintf("Malformed metadata markdown in %s, must be of the form: YAML\\n---\\nmarkdown content", path))
return nil, errors.New(fmt.Sprintf("Malformed metadata markdown in %s, must be of the form: YAML\\n---\\nmarkdown content", path))
}
yaml := components[0]
item := components[0]
body := strings.Join(components[1:], "---")
return metadataMarkdown{yaml, body}
return &metadataMarkdown{item, body}, nil
}

258
internal/model/fs_test.go Normal file
View File

@ -0,0 +1,258 @@
package model
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/strongdm/comply/internal/config"
"github.com/strongdm/comply/internal/path"
"gopkg.in/yaml.v2"
)
// TestReadNarratives calls model.ReadNarratives checking for a valid return value.
func TestReadNarratives(t *testing.T) {
mockConfig()
filePath := fmt.Sprintf("%s/narratives/control.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
path.Narratives = func() ([]path.File, error) {
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
documents, err := ReadNarratives()
if err != nil {
t.Fatalf(`ReadNarratives() returned an error %v`, err)
}
if len(documents) != 1 {
t.Fatal(`Invalid number of documents`)
}
if documents[0].FullPath != filePath {
t.Fatalf(`Invalid document path %s`, documents[0].FullPath)
}
}
// TestReadNarrativesWhenThereAreNoNarratives calls model.ReadNarratives checking for a valid return when
// there are no narratives to process
func TestReadNarrativesWhenThereAreNoNarratives(t *testing.T) {
mockConfig()
path.Narratives = func() ([]path.File, error) {
return []path.File{}, nil
}
documents, err := ReadNarratives()
if err != nil {
t.Fatalf(`ReadNarratives() returned an error %v`, err)
}
if len(documents) != 0 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadNarrativesFailsWhenInvalidNarrative calls model.ReadNarratives checking for an error return when
// there is an invalid narrative
func TestReadNarrativesFailsWhenInvalidNarrative(t *testing.T) {
mockConfig()
path.Narratives = func() ([]path.File, error) {
filePath := fmt.Sprintf("%s/../fixtures/narratives/invalid-control.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
_, err := ReadNarratives()
if err == nil {
t.Fatal(`ReadNarratives() was expected to fail`)
}
}
// TestReadProcedures calls model.ReadProcedures checking for a valid return value.
func TestReadProcedures(t *testing.T) {
mockConfig()
filePath := fmt.Sprintf("%s/procedures/workstation.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
path.Procedures = func() ([]path.File, error) {
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
documents, err := ReadProcedures()
if err != nil {
t.Fatalf(`ReadProcedures() returned an error %v`, err)
}
if len(documents) != 1 {
t.Fatal(`Invalid number of documents`)
}
if documents[0].FullPath != filePath {
t.Fatalf(`Invalid document path %s`, documents[0].FullPath)
}
}
// TestReadProceduresWhenThereAreNoProcedures calls model.ReadProcedures checking for a valid return when
// there are no procedures to process
func TestReadProceduresWhenThereAreNoProcedures(t *testing.T) {
mockConfig()
path.Procedures = func() ([]path.File, error) {
return []path.File{}, nil
}
documents, err := ReadProcedures()
if err != nil {
t.Fatalf(`ReadProcedures() returned an error %v`, err)
}
if len(documents) != 0 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadProceduresFailsWhenInvalidProcedure calls model.ReadProcedures checking for an error return when
// there is an invalid procedure
func TestReadProceduresFailsWhenInvalidProcedure(t *testing.T) {
mockConfig()
path.Procedures = func() ([]path.File, error) {
filePath := fmt.Sprintf("%s/../fixtures/procedures/invalid-workstation.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
_, err := ReadProcedures()
if err == nil {
t.Fatal(`ReadProcedures() was expected to fail`, err)
}
}
// TestReadPolicies calls model.ReadPolicies checking for a valid return value.
func TestReadPolicies(t *testing.T) {
mockConfig()
filePath := fmt.Sprintf("%s/policies/access.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
path.Policies = func() ([]path.File, error) {
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
documents, err := ReadPolicies()
if err != nil {
t.Fatalf(`ReadPolicies() returned an error %v`, err)
}
if len(documents) != 1 {
t.Fatal(`Invalid number of documents`)
}
if documents[0].FullPath != filePath {
t.Fatalf(`Invalid document path %s`, documents[0].FullPath)
}
}
// TestReadPoliciesWhenThereAreNoPolicies calls model.ReadPolicies checking for a valid return when
// there are no policies to process
func TestReadPoliciesWhenThereAreNoPolicies(t *testing.T) {
mockConfig()
path.Policies = func() ([]path.File, error) {
return []path.File{}, nil
}
documents, err := ReadPolicies()
if err != nil {
t.Fatalf(`ReadPolicies() returned an error %v`, err)
}
if len(documents) != 0 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadPoliciesFailsWhenInvalidPolicy calls model.ReadPolicies checking for an error return when
// there is an invalid policy
func TestReadPoliciesFailsWhenInvalidPolicy(t *testing.T) {
mockConfig()
path.Policies = func() ([]path.File, error) {
filePath := fmt.Sprintf("%s/../fixtures/policies/invalid-access.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
_, err := ReadPolicies()
if err == nil {
t.Fatal(`ReadPolicies() was expected to fail`, err)
}
}
// TestReadStandards calls model.ReadStandards checking for a valid return value.
func TestReadStandards(t *testing.T) {
mockConfig()
filePath := fmt.Sprintf("%s/standards/TSC-2017.yml", getRootPath())
fileInfo, _ := os.Lstat(filePath)
path.Standards = func() ([]path.File, error) {
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
documents, err := ReadStandards()
if err != nil {
t.Fatalf(`ReadStandards() returned an error %v`, err)
}
if len(documents) != 1 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadStandardsWhenThereAreNoStandards calls model.ReadStandards checking for a valid return when
// there are no standards to process
func TestReadStandardsWhenThereAreNoStandards(t *testing.T) {
mockConfig()
path.Standards = func() ([]path.File, error) {
return []path.File{}, nil
}
documents, err := ReadStandards()
if err != nil {
t.Fatalf(`ReadStandards() returned an error %v`, err)
}
if len(documents) != 0 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadStandardsFailsWhenInvalidStandard calls model.ReadStandards checking for an error return when
// there is an invalid standard
func TestReadStandardsFailsWhenInvalidStandard(t *testing.T) {
mockConfig()
path.Standards = func() ([]path.File, error) {
filePath := fmt.Sprintf("%s/../fixtures/standards/invalid-standard.yml", getRootPath())
fileInfo, _ := os.Lstat(filePath)
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
_, err := ReadStandards()
if err == nil {
t.Fatal(`ReadStandards() was expected to fail`, err)
}
}
func mockConfig() {
config.Config = func() *config.Project {
p := config.Project{}
cfgBytes, _ := ioutil.ReadFile(filepath.Join(getRootPath(), "comply.yml.example"))
yaml.Unmarshal(cfgBytes, &p)
return &p
}
}
func getRootPath() string {
_, fileName, _, _ := runtime.Caller(0)
fileDir := filepath.Dir(fileName)
return fmt.Sprintf("%s/../../example", fileDir)
}

View File

@ -9,22 +9,22 @@ import (
func TestMarshal(t *testing.T) {
d := Data{
Tickets: []*Ticket{
&Ticket{
{
ID: "t1",
},
},
Audits: []*Audit{
&Audit{
{
ID: "a1",
},
},
Procedures: []*Procedure{
&Procedure{
Code: "pro1",
{
ID: "pro1",
},
},
Policies: []*Policy{
&Policy{
Policies: []*Document{
{
Name: "pol1",
},
},
@ -40,5 +40,4 @@ func TestMarshal(t *testing.T) {
!strings.Contains(encoded, "pol1") {
t.Error("identifier not found in marshalled string")
}
}

View File

@ -16,22 +16,22 @@ type File struct {
}
// Standards lists all standard files.
func Standards() ([]File, error) {
var Standards = func() ([]File, error) {
return filesFor("standards", "yml")
}
// Narratives lists all narrative files.
func Narratives() ([]File, error) {
var Narratives = func() ([]File, error) {
return filesFor("narratives", "md")
}
// Policies lists all policy files.
func Policies() ([]File, error) {
var Policies = func() ([]File, error) {
return filesFor("policies", "md")
}
// Procedures lists all procedure files.
func Procedures() ([]File, error) {
var Procedures = func() ([]File, error) {
return filesFor("procedures", "md")
}