mirror of
https://github.com/strongdm/comply
synced 2025-04-10 17:33:28 +00:00
Compare commits
No commits in common. "v0.0.2" and "master" have entirely different histories.
.env.example.gitignore.gitmodulesAUTHORS.txtDockerfileGopkg.lockGopkg.tomlMakefileREADME.mdSUPPORT.mdVERSIONgo.modgo.sum
build
cmd/comply
comply.gocomply.rbexample
README.mdTODO.mdcomply.yml.example
narratives
policies
README.mdaccess.mdapplication.mdavailability.mdchange.mdclassification.mdconduct.mdconfidentiality.mdcontinuity.mdcyber.mddatacenter.mddevelopment.mddisaster.mdencryption.mdincident.mdinformation.mdlog.mdmedia.mdoffice.mdpassword.mdpolicy.mdprivacy.mdprocessing.mdremote.mdretention.mdrisk.mdvendor.mdworkstation.md
procedures
standards
templates
fixtures
narratives
policies
procedures
standards
internal
cli
config
gitlab
jira
model
path
plugin/github
render
theme
1
.env.example
Normal file
1
.env.example
Normal file
@ -0,0 +1 @@
|
||||
COMPLY_USE_LOCAL_PANDOC=
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,2 +1,8 @@
|
||||
comply
|
||||
output
|
||||
dist
|
||||
.envrc
|
||||
bindata.go
|
||||
.idea/
|
||||
.env
|
||||
.vscode/
|
||||
|
0
.gitmodules
vendored
0
.gitmodules
vendored
@ -1,3 +1,12 @@
|
||||
# Authors in alphabetical order:
|
||||
|
||||
arambhashura
|
||||
Alan Cox
|
||||
Andy Magnusson
|
||||
Anthony Oliver
|
||||
Justin Bodeutsch
|
||||
Justin McCarthy <justin@strongdm.com>
|
||||
Kevin N. Murphy
|
||||
Manisha Singh
|
||||
Mason Hensley
|
||||
Matt Simerson
|
21
Dockerfile
Normal file
21
Dockerfile
Normal file
@ -0,0 +1,21 @@
|
||||
FROM strongdm/pandoc:edge
|
||||
|
||||
# based on implementation by James Gregory <james@jagregory.com>
|
||||
MAINTAINER Comply <comply@strongdm.com>
|
||||
|
||||
RUN apt-get update -y \
|
||||
&& apt-get install -y curl
|
||||
|
||||
ARG COMPLY_VERSION
|
||||
ENV COMPLY_VERSION ${COMPLY_VERSION:-1.6.0}
|
||||
|
||||
EXPOSE 4000/tcp
|
||||
|
||||
# install comply binary
|
||||
RUN curl -J -L -o /tmp/comply.tgz https://github.com/strongdm/comply/releases/download/v${COMPLY_VERSION}/comply-v${COMPLY_VERSION}-linux-amd64.tgz \
|
||||
&& tar -xzf /tmp/comply.tgz \
|
||||
&& mv ./comply-v${COMPLY_VERSION}-linux-amd64 /usr/local/bin/comply
|
||||
|
||||
WORKDIR /source
|
||||
|
||||
ENTRYPOINT ["/bin/bash"]
|
262
Gopkg.lock
generated
262
Gopkg.lock
generated
@ -1,262 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Microsoft/go-winio"
|
||||
packages = ["."]
|
||||
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
|
||||
version = "v0.4.7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/chzyer/readline"
|
||||
packages = ["."]
|
||||
revision = "f6d7a1f6fbf35bbf9beb80dc63c56a29dcfb759f"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/distribution"
|
||||
packages = [
|
||||
"digest",
|
||||
"reference"
|
||||
]
|
||||
revision = "48294d928ced5dd9b378f7fd7c6f5da3ff3f2c89"
|
||||
version = "v2.6.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/docker"
|
||||
packages = [
|
||||
"api/types",
|
||||
"api/types/blkiodev",
|
||||
"api/types/container",
|
||||
"api/types/events",
|
||||
"api/types/filters",
|
||||
"api/types/mount",
|
||||
"api/types/network",
|
||||
"api/types/reference",
|
||||
"api/types/registry",
|
||||
"api/types/strslice",
|
||||
"api/types/swarm",
|
||||
"api/types/time",
|
||||
"api/types/versions",
|
||||
"api/types/volume",
|
||||
"client",
|
||||
"pkg/tlsconfig"
|
||||
]
|
||||
revision = "092cba3727bb9b4a2f0e922cd6c0f93ea270e363"
|
||||
version = "v1.13.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/go-connections"
|
||||
packages = [
|
||||
"nat",
|
||||
"sockets",
|
||||
"tlsconfig"
|
||||
]
|
||||
revision = "3ede32e2033de7505e6500d6c868c2b9ed9f169d"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/go-units"
|
||||
packages = ["."]
|
||||
revision = "0dadbb0345b35ec7ef35e228dabb8de89a65bf52"
|
||||
version = "v0.3.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/elazarl/go-bindata-assetfs"
|
||||
packages = ["."]
|
||||
revision = "30f82fa23fd844bd5bb1e5f216db87fd77b5eb43"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fatih/color"
|
||||
packages = ["."]
|
||||
revision = "507f6050b8568533fb3f5504de8e5205fa62a114"
|
||||
version = "v1.6.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gohugoio/hugo"
|
||||
packages = ["watcher"]
|
||||
revision = "f414966b942b5aad75565bee6c644782a07f0658"
|
||||
version = "v0.37.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = ["proto"]
|
||||
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/google/go-github"
|
||||
packages = ["github"]
|
||||
revision = "e48060a28fac52d0f1cb758bc8b87c07bac4a87d"
|
||||
version = "v15.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/google/go-querystring"
|
||||
packages = ["query"]
|
||||
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
packages = ["."]
|
||||
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/jcelliott/lumber"
|
||||
packages = ["."]
|
||||
revision = "dd349441af25132d146d7095c6693a15431fc9b1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/juju/ansiterm"
|
||||
packages = [
|
||||
".",
|
||||
"tabwriter"
|
||||
]
|
||||
revision = "720a0952cc2ac777afc295d9861263e2a4cf96a1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/lunixbochs/vtclean"
|
||||
packages = ["."]
|
||||
revision = "d14193dfc626125c831501c1c42340b4248e1f5a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/manifoldco/promptui"
|
||||
packages = [
|
||||
".",
|
||||
"list",
|
||||
"screenbuf"
|
||||
]
|
||||
revision = "c0c0d3afc6a03bcb5c1df10b70b862a650db9f9b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-runewidth"
|
||||
packages = ["."]
|
||||
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/nanobox-io/golang-scribble"
|
||||
packages = ["."]
|
||||
revision = "ced58d671850da57ce8c11315424513b608083d7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/olekukonko/tablewriter"
|
||||
packages = ["."]
|
||||
revision = "b8a9be070da40449e501c3c4730a889e42d87a9e"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/robfig/cron"
|
||||
packages = ["."]
|
||||
revision = "b024fc5ea0e34bc3f83d9941c8d60b0622bfaca4"
|
||||
version = "v1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/skratchdot/open-golang"
|
||||
packages = ["open"]
|
||||
revision = "75fb7ed4208cf72d323d7d02fd1a5964a7a9073c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/urfave/cli"
|
||||
packages = ["."]
|
||||
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
|
||||
version = "v1.20.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/yosssi/ace"
|
||||
packages = ["."]
|
||||
revision = "ea038f4770b6746c3f8f84f14fa60d9fe1205b56"
|
||||
version = "v0.0.5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"context/ctxhttp",
|
||||
"proxy"
|
||||
]
|
||||
revision = "d0aafc73d5cdc42264b0af071c261abac580695e"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/oauth2"
|
||||
packages = [
|
||||
".",
|
||||
"internal"
|
||||
]
|
||||
revision = "7af32f14d0a25aec7873e0683e8e48dcead159a8"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows"
|
||||
]
|
||||
revision = "dd2ff4accc098aceecb86b36eaa7829b2a17b1c9"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/appengine"
|
||||
packages = [
|
||||
"internal",
|
||||
"internal/base",
|
||||
"internal/datastore",
|
||||
"internal/log",
|
||||
"internal/remote_api",
|
||||
"internal/urlfetch",
|
||||
"urlfetch"
|
||||
]
|
||||
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5"
|
||||
version = "v2.1.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "4fd2ff9f9869c3f3e30601504f4b00fce69d282ae8df42583a1c60848bfd0766"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
30
Gopkg.toml
30
Gopkg.toml
@ -1,30 +0,0 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
125
Makefile
125
Makefile
@ -3,26 +3,57 @@ GO_SOURCES := $(shell find . -name '*.go')
|
||||
THEME_SOURCES := $(shell find themes)
|
||||
|
||||
assets: $(THEME_SOURCES)
|
||||
go install -mod=vendor github.com/containous/go-bindata/go-bindata
|
||||
go install -mod=vendor github.com/elazarl/go-bindata-assetfs/go-bindata-assetfs
|
||||
go-bindata-assetfs -pkg theme -prefix themes themes/...
|
||||
mv bindata_assetfs.go internal/theme/themes_bindata.go
|
||||
mv bindata.go internal/theme/themes_bindata.go
|
||||
|
||||
comply: assets $(GO_SOURCES)
|
||||
go build github.com/strongdm/comply/cmd/comply
|
||||
@# $(eval VERSION := $(shell git describe --tags --always --dirty="-dev"))
|
||||
@# $(eval LDFLAGS := -ldflags='-X "github.com/strongdm/comply/internal/cli.Version=$(VERSION)"')
|
||||
go build $(LDFLAGS) github.com/strongdm/comply
|
||||
|
||||
dist: clean
|
||||
$(eval VERSION := $(shell git describe --tags --always --dirty="-dev"))
|
||||
$(eval LDFLAGS := -ldflags='-X "github.com/strongdm/comply/internal/cli.Version=$(VERSION)"')
|
||||
mkdir dist
|
||||
echo $(VERSION)
|
||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -gcflags=-trimpath=$(GOPATH) -asmflags=-trimpath=$(GOPATH) -ldflags '-extldflags "-static"' $(LDFLAGS) -o dist/comply-$(VERSION)-darwin-amd64 .
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -gcflags=-trimpath=$(GOPATH) -asmflags=-trimpath=$(GOPATH) -ldflags '-extldflags "-static"' $(LDFLAGS) -o dist/comply-$(VERSION)-linux-amd64 .
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -gcflags=-trimpath=$(GOPATH) -asmflags=-trimpath=$(GOPATH) -ldflags '-extldflags "-static"' $(LDFLAGS) -o dist/comply-$(VERSION)-windows-amd64.exe .
|
||||
cd dist && tar -czvf comply-$(VERSION)-darwin-amd64.tgz comply-$(VERSION)-darwin-amd64
|
||||
cd dist && tar -czvf comply-$(VERSION)-linux-amd64.tgz comply-$(VERSION)-linux-amd64
|
||||
cd dist && zip comply-$(VERSION)-windows-amd64.zip comply-$(VERSION)-windows-amd64.exe
|
||||
|
||||
brew: clean $(GO_SOURCES)
|
||||
$(eval VERSION := $(shell cat version))
|
||||
$(eval LDFLAGS := -ldflags='-X "github.com/strongdm/comply/internal/cli.Version=$(VERSION)"')
|
||||
mkdir bin
|
||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -gcflags=-trimpath=$(GOPATH) -asmflags=-trimpath=$(GOPATH) $(LDFLAGS) -o bin/comply .
|
||||
|
||||
clean:
|
||||
rm -rf bin
|
||||
rm -rf dist
|
||||
rm -f comply
|
||||
|
||||
install: assets $(GO_SOURCES)
|
||||
go install github.com/strongdm/comply/cmd/comply
|
||||
go install github.com/strongdm/comply
|
||||
|
||||
export-example:
|
||||
cp example/narratives/* themes/comply-soc2/narratives
|
||||
cp example/procedures/* themes/comply-soc2/procedures
|
||||
cp example/policies/* themes/comply-soc2/policies
|
||||
cp example/standards/* themes/comply-soc2/standards
|
||||
cp example/templates/* themes/comply-soc2/templates
|
||||
push-assets: is-clean assets
|
||||
git commit -am "automated asset refresh (via Makefile)"
|
||||
git push
|
||||
|
||||
is-clean:
|
||||
ifeq ($(strip $(shell git status --porcelain 2>/dev/null)),)
|
||||
# good to proceed
|
||||
else
|
||||
@echo working directory must be clean to proceed
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
docker:
|
||||
cd build && docker build -t strongdm/pandoc .
|
||||
docker tag jagregory/pandoc:latest strongdm/pandoc:latest
|
||||
docker push strongdm/pandoc
|
||||
cd build && docker build -t strongdm/pandoc:edge .
|
||||
docker push strongdm/pandoc:edge
|
||||
|
||||
cleanse:
|
||||
git checkout --orphan newbranch
|
||||
@ -33,3 +64,73 @@ cleanse:
|
||||
git push -f origin master
|
||||
git gc --aggressive --prune=all
|
||||
|
||||
release-env:
|
||||
ifndef GH_LOGIN
|
||||
$(error GH_LOGIN must be set to a valid GitHub token)
|
||||
endif
|
||||
ifndef COMPLY_TAPDIR
|
||||
$(error COMPLY_TAPDIR must be set to the path of the comply homebrew tap repo)
|
||||
endif
|
||||
ifndef COMPLY_RELEASE_WEBHOOK
|
||||
$(error COMPLY_RELEASE_WEBHOOK must be set to a webhook for the release Slack channel)
|
||||
endif
|
||||
|
||||
release: release-env dist release-deps
|
||||
$(eval VERSION := $(shell git describe --tags --always --dirty="-dev"))
|
||||
github-release release \
|
||||
--security-token $$GH_LOGIN \
|
||||
--user strongdm \
|
||||
--repo comply \
|
||||
--tag $(VERSION) \
|
||||
--name $(VERSION)
|
||||
|
||||
github-release upload \
|
||||
--security-token $$GH_LOGIN \
|
||||
--user strongdm \
|
||||
--repo comply \
|
||||
--tag $(VERSION) \
|
||||
--name comply-$(VERSION)-darwin-amd64.tgz \
|
||||
--file dist/comply-$(VERSION)-darwin-amd64.tgz
|
||||
|
||||
github-release upload \
|
||||
--security-token $$GH_LOGIN \
|
||||
--user strongdm \
|
||||
--repo comply \
|
||||
--tag $(VERSION) \
|
||||
--name comply-$(VERSION)-linux-amd64.tgz \
|
||||
--file dist/comply-$(VERSION)-linux-amd64.tgz
|
||||
|
||||
@echo "Update homebrew formula with the following: "
|
||||
$(eval SHA := $(shell curl -s -L https://github.com/strongdm/comply/archive/$(VERSION).tar.gz |shasum -a 256|cut -d" " -f1))
|
||||
@echo "version $(VERSION) sha $(SHA)"
|
||||
cd $$COMPLY_TAPDIR && ./update.sh $(VERSION) $(SHA)
|
||||
|
||||
patch-release: release-env patch release
|
||||
$(eval VERSION := $(shell git describe --tags --always --dirty="-dev"))
|
||||
curl -X POST --data-urlencode 'payload={"channel": "#release", "username": "release", "text": "comply $(VERSION) released", "icon_emoji": ":shipit:"}' $$COMPLY_RELEASE_WEBHOOK
|
||||
|
||||
minor-release: release-env minor release
|
||||
$(eval VERSION := $(shell git describe --tags --always --dirty="-dev"))
|
||||
curl -X POST --data-urlencode 'payload={"channel": "#release", "username": "release", "text": "comply $(VERSION) released", "icon_emoji": ":shipit:"}' $$COMPLY_RELEASE_WEBHOOK
|
||||
|
||||
docker-release:
|
||||
docker build --build-arg COMPLY_VERSION=`cat VERSION` -t strongdm/comply .
|
||||
docker push strongdm/comply
|
||||
|
||||
patch: clean gitsem
|
||||
gitsem -m "increment patch for release (via Makefile)" patch
|
||||
git push
|
||||
git push origin --tags
|
||||
|
||||
minor: clean gitsem
|
||||
gitsem -m "increment minor for release (via Makefile)" minor
|
||||
git push
|
||||
git push origin --tags
|
||||
|
||||
release-deps: gitsem gh-release
|
||||
|
||||
gitsem:
|
||||
go install github.com/Clever/gitsem
|
||||
|
||||
gh-release:
|
||||
go install github.com/aktau/github-release
|
158
README.md
158
README.md
@ -1,26 +1,66 @@
|
||||
# Comply
|
||||

|
||||
|
||||
Comply is a SOC2-focused compliance automation tool. Comply features a markdown-powered **document pipeline** and a git-powered **workflow** that help policies and procedures _feel_ like software development.
|
||||
Comply is a SOC2-focused compliance automation tool:
|
||||
|
||||
Comply manages the lifecycle of your program throughout the year via your existing **ticketing system**.
|
||||
- **Policy Generator**: markdown-powered **document pipeline** for publishing auditor-friendly **policy documents**
|
||||
- **Ticketing Integration**: automate compliance throughout the year via your existing **ticketing system**
|
||||
- **SOC2 Templates**: open source policy and procedure **templates** suitable for satisfying a SOC2 audit
|
||||
|
||||
In addition to automation, Comply includes a SOC2-focused module featuring open source policy and procedure **templates** suitable for satisfying a SOC2 audit.
|
||||
# Installation
|
||||
|
||||
macOS:
|
||||
|
||||
`brew tap strongdm/comply; brew install comply`
|
||||
|
||||
Linux:
|
||||
|
||||
[Download latest release](https://github.com/strongdm/comply/releases)
|
||||
|
||||
Go users:
|
||||
|
||||
`go get github.com/strongdm/comply`
|
||||
|
||||
# Get Started
|
||||
|
||||
Start with `comply init`:
|
||||
|
||||
```
|
||||
$ mkdir my-company
|
||||
$ cd my-company
|
||||
$ comply init
|
||||
```
|
||||
|
||||
Once `comply init` is complete, just `git init` and `git push` your project to a new repository. You're ready to begin editing the included policy boilerplate text.
|
||||
|
||||
# Discussion
|
||||
|
||||
Join us in [Comply Users](https://join.slack.com/t/comply-users/shared_invite/enQtMzU3MTk5MDkxNDU4LTMwYzZkMjA4YjQ2YTM5Zjc0NTAyYWY5MDBlOGMwMzRmZTk5YzBlOTRiMTVlNGRlZjY1MTY1NDE0MjY5ZjYwNWU)
|
||||
Join us in [Comply Users](https://join.slack.com/t/comply-users/shared_invite/zt-4k3f46wy-Cs1DceznNvAL~lnW9_HjIA)
|
||||
|
||||
# Screenshots
|
||||
|
||||
[Demo video](https://vimeo.com/270257486)
|
||||
|
||||
## Start a Project
|
||||
|
||||

|
||||
|
||||
## Build PDFs
|
||||
|
||||

|
||||

|
||||
|
||||
## Track Policy Coverage
|
||||
|
||||

|
||||
|
||||
## Dashboard
|
||||
|
||||

|
||||
|
||||
## Dependencies
|
||||
|
||||
Comply relies on [pandoc](https://pandoc.org/), which can be installed directly as an OS package or invoked via Docker.
|
||||
|
||||
## CLI
|
||||
|
||||
```
|
||||
@ -31,14 +71,102 @@ USAGE:
|
||||
comply [global options] command [command options] [arguments...]
|
||||
|
||||
COMMANDS:
|
||||
build, b generate a static website summarizing the compliance program
|
||||
init initialize a new compliance repository (interactive)
|
||||
scheduler create tickets based on procedure schedule
|
||||
serve live updating version of the build command
|
||||
sync sync external systems to local data cache
|
||||
todo list declared vs satisfied compliance controls
|
||||
help, h Shows a list of commands or help for one command
|
||||
init initialize a new compliance repository (interactive)
|
||||
build, b generate a static website summarizing the compliance program
|
||||
procedure, proc create ticket by procedure ID
|
||||
scheduler create tickets based on procedure schedule
|
||||
serve live updating version of the build command
|
||||
sync sync ticket status to local cache
|
||||
todo list declared vs satisfied compliance controls
|
||||
help, h Shows a list of commands or help for one command
|
||||
```
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--help, -h show help
|
||||
```
|
||||
## Running in Docker
|
||||
|
||||
Comply is currently only released for Linux and macOS, however from other operating systems it's possible to run using Docker:
|
||||
|
||||
```
|
||||
# first pull the latest published docker image
|
||||
$ docker pull strongdm/comply
|
||||
|
||||
# from an empty directory that will contain your comply project
|
||||
$ docker run --rm -v "$PWD":/source -p 4000:4000 -it strongdm/comply
|
||||
root@ec4544732298:/source# comply init
|
||||
✗ Organization Name:
|
||||
|
||||
# serve content live from an established project
|
||||
$ docker run --rm -v "$PWD":/source -p 4000:4000 -it strongdm/comply
|
||||
root@ae4d499583fc:/source# comply serve
|
||||
Serving content of output/ at http://127.0.0.1:4000 (ctrl-c to quit)
|
||||
```
|
||||
|
||||
For Windows users, replace $PWD with the full path to your project directory
|
||||
|
||||
### Running in macOS M1
|
||||
|
||||
If you're running Comply inside Docker, or using it installed by HomeBrew, in a macOS M1, you should increase the Docker allocatable memory space to ~7 GB, but it won't run smoothly. So, we recommend to run Comply locally with pandoc binary installed via HomeBrew. For that, install the `pandoc` and `basictex` packages using the following command:
|
||||
|
||||
```bash
|
||||
brew install pandoc basictex
|
||||
```
|
||||
|
||||
Then when running the Comply binary -installed by HomeBrew- it will work as expected.
|
||||
|
||||
## Ticketing Integrations:
|
||||
|
||||
- Jira
|
||||
- Github
|
||||
- Gitlab
|
||||
|
||||
## Configuration
|
||||
|
||||
## GitHub
|
||||
|
||||
Ticketing integration with GitHub can be configured with the following YAML in `comply.yml`:
|
||||
|
||||
```yaml
|
||||
tickets:
|
||||
github:
|
||||
repo: <repo-name>
|
||||
token: <token>
|
||||
username: org or personal username
|
||||
```
|
||||
|
||||
If you're setting up the repo in your personal account, set `username` to your username.
|
||||
If you're setting up the repo in an github organization, set `username` to your org's username instead.
|
||||
|
||||
Also, `GITHUB_REPO`, `GITHUB_TOKEN`, and `GITHUB_USERNAME` can be used to override values from the YAML file.
|
||||
|
||||
### Jira
|
||||
|
||||
When comply creates a ticket (through `proc`, for instance), it sets the following fields.
|
||||
|
||||
- assignee
|
||||
- description
|
||||
- issuetype
|
||||
- labels
|
||||
- project key
|
||||
- reporter
|
||||
- summary
|
||||
|
||||
Please make sure that the default _Create Screen_ has all of those fields enabled. Additionally, make sure that there are no other required fields for the issue type you choose.
|
||||
|
||||
About authentication, you need to create an [API Token](https://id.atlassian.com/manage-profile/security/api-tokens) to use as a password.
|
||||
|
||||
## Forking and local development
|
||||
|
||||
> Assumes installation of golang and configuration of GOPATH in .bash_profile, .zshrc, etc
|
||||
> Inspiration: http://code.openark.org/blog/development/forking-golang-repositories-on-github-and-managing-the-import-path
|
||||
|
||||
```
|
||||
$ go get github.com/strongdm/comply
|
||||
$ cd $GOPATH/src/github.com/strongdm/comply ; go get ./...
|
||||
$ make
|
||||
$ cd example
|
||||
$ mv comply.yml.example comply.yml
|
||||
$ ../comply -h
|
||||
$ ../comply sync
|
||||
$ ../comply serve
|
||||
#
|
||||
$ make # recompile as needed with in $GOPATH/src/github.com/strongdm/comply
|
||||
```
|
||||
|
5
SUPPORT.md
Normal file
5
SUPPORT.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Support
|
||||
|
||||
All questions/support related to Comply would be kindly addressed by the community, you can reach out to us via:
|
||||
* [Issues](https://github.com/strongdm/comply/issues), or
|
||||
* [Slack](https://join.slack.com/t/comply-users/shared_invite/zt-4k3f46wy-Cs1DceznNvAL~lnW9_HjIA)
|
1
VERSION
Normal file
1
VERSION
Normal file
@ -0,0 +1 @@
|
||||
1.6.0
|
@ -1,3 +1,10 @@
|
||||
FROM scratch
|
||||
FROM pandoc/ubuntu
|
||||
|
||||
MAINTAINER strongDM Comply <comply@strongdm.com>
|
||||
RUN apt-get update -y \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -y -o Acquire::Retries=10 --no-install-recommends \
|
||||
texlive-latex-base \
|
||||
texlive-latex-extra \
|
||||
texlive-plain-generic \
|
||||
lmodern
|
||||
|
||||
WORKDIR /source
|
||||
|
@ -1,7 +0,0 @@
|
||||
package main
|
||||
|
||||
import "github.com/strongdm/comply/internal/cli"
|
||||
|
||||
func main() {
|
||||
cli.Main()
|
||||
}
|
17
comply.go
Normal file
17
comply.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/strongdm/comply/internal/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, b, _, _ := runtime.Caller(0)
|
||||
basepath := filepath.Dir(b)
|
||||
godotenv.Load(fmt.Sprintf("%s/.env", basepath))
|
||||
cli.Main()
|
||||
}
|
22
comply.rb
Normal file
22
comply.rb
Normal file
@ -0,0 +1,22 @@
|
||||
class Comply < Formula
|
||||
desc ""
|
||||
homepage ""
|
||||
url "file:///Users/jmccarthy/Downloads/comply-1.1.3.tgz"
|
||||
sha256 "01f9920e5e9fbd29386e4a4131fac78c002730e49c3f870a0ee2b958c3ce75f6"
|
||||
|
||||
depends_on "go" => :build
|
||||
|
||||
def install
|
||||
ENV["GOPATH"] = buildpath
|
||||
ENV.prepend_create_path "PATH", buildpath/"bin"
|
||||
(buildpath/"src/github.com/strongdm/comply").install buildpath.children
|
||||
cd "src/github.com/strongdm/comply" do
|
||||
system "make", "brew"
|
||||
bin.install "bin/comply"
|
||||
end
|
||||
end
|
||||
|
||||
test do
|
||||
system "#{bin}/sdm", "logout"
|
||||
end
|
||||
end
|
@ -1 +1,60 @@
|
||||
# Acme Compliance
|
||||
# {{.Name}} Compliance Program
|
||||
|
||||
This repository consolidates all documents related to the {{.Name}} Compliance Program.
|
||||
|
||||
# Structure
|
||||
|
||||
Compliance documents are organized as follows:
|
||||
|
||||
```
|
||||
narratives/ Narratives provide an overview of the organization and the compliance environment.
|
||||
policies/ Policies govern the behavior of employees and contractors.
|
||||
procedures/ Procedures prescribe specific steps that are taken in response to key events.
|
||||
standards/ Standards specify the controls satisfied by the compliance program.
|
||||
templates/ Templates control the output format of the HTML Dashboard and PDF assets.
|
||||
```
|
||||
|
||||
# Building
|
||||
|
||||
Assets are built using [`comply`](https://comply.strongdm.com), which can be installed via `brew install comply` (macOS) or `go get github.com/strongdm/comply`
|
||||
|
||||
# Publishing
|
||||
|
||||
The `output/` directory contains all generated assets. Links in the HTML dashboard are relative, and all dependencies are included via direct CDN references. The entire `output/` directory, therefore, may be uploaded to an S3 bucket or another static asset host without further modification.
|
||||
|
||||
# Dashboard Status
|
||||
|
||||
Procedure tracking is updated whenever `comply sync` is invoked. Invoke a sync prior to `comply build` to include the most current ticket status.
|
||||
|
||||
# Procedure Scheduler
|
||||
|
||||
Any `procedures/` that include a `cron` schedule will automatically created in your configured ticketing system whenever `comply scheduler` is executed. The scheduler will backfill any overdue tickets.
|
||||
|
||||
# Deployment Recommendation
|
||||
|
||||
Invoke a script similar to the following at least once per day:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
#
|
||||
# prerequisites:
|
||||
# git access
|
||||
# ticketing configuration in comply.yml
|
||||
# upload.sh to publish static site
|
||||
#
|
||||
|
||||
# get latest policies and procedures
|
||||
git pull
|
||||
|
||||
# update ticketing status
|
||||
comply sync
|
||||
|
||||
# trigger creation of scheduled tickets
|
||||
comply scheduler
|
||||
|
||||
# build latest
|
||||
comply build
|
||||
|
||||
# publish static site from output/ directory
|
||||
upload.sh output/
|
||||
```
|
||||
|
37
example/TODO.md
Normal file
37
example/TODO.md
Normal file
@ -0,0 +1,37 @@
|
||||
# {{.Name}} Compliance Program
|
||||
|
||||
High-level TODO created by [comply](https://github.com/strongdm/comply)
|
||||
|
||||
## Initialization Phase (hours)
|
||||
- [ ] Add project to source control
|
||||
- [ ] Verify `comply build` generates valid output
|
||||
- [ ] Create ticketing credentials, configure via `comply.yml`
|
||||
- [ ] Verify `comply sync` executes without errors
|
||||
|
||||
## Authoring Phase (weeks)
|
||||
- [ ] Validate standards/, pruning as necessary
|
||||
- [ ] Customize narratives/
|
||||
- [ ] Customize policies/
|
||||
- [ ] Distribute controls among policies
|
||||
- [ ] Ensure policies address all controls
|
||||
- [ ] Customize procedures/
|
||||
- [ ] Distribute controls among procedures
|
||||
- [ ] Create valid ticket templates
|
||||
- [ ] Assign schedules
|
||||
- [ ] Verify `comply todo` indicates all controls satisfied
|
||||
|
||||
## Deployment Phase (weeks)
|
||||
- [ ] Deploy `comply scheduler` (see README.md for example script)
|
||||
- [ ] Deploy `comply build` output to shared location
|
||||
- [ ] Distribute policies to team
|
||||
- [ ] Train team on use of ticketing system to designate compliance-relevant activity
|
||||
|
||||
## Operating Phase (eternal)
|
||||
- [ ] Monitor timely ticket workflow
|
||||
- [ ] Adjust and re-publish narratives, policies and procedures as necessary
|
||||
|
||||
## Audit Phase (weeks, annually)
|
||||
- [ ] Import request list (tickets will be generated)
|
||||
- [ ] Fulfill all request tickets
|
||||
- [ ] Attach policies, procedures, and narratives
|
||||
- [ ] Attach evidence collected by previously-executed procedure tickets
|
@ -1,9 +1,31 @@
|
||||
programName: "Acme Compliance"
|
||||
regimes:
|
||||
- "SOC2"
|
||||
- "ISO 27001"
|
||||
name: "Acme"
|
||||
filePrefix: "Acme"
|
||||
|
||||
# The following setting is optional.
|
||||
# If you set this (to, e.g. master), and you build the policies
|
||||
# on that branch, then a section is appended to each policy that
|
||||
# describes the approval. Text will look like:
|
||||
#
|
||||
# Last edit made by John Doe (jdoe@email.com) on Wed, 15 Aug 2018 12:45:28 -0400.
|
||||
# Approved by Joan Smith (jsmith@email.com) on Wed, 15 Aug 2018 16:54:48 -0400 in commit abc123123.
|
||||
#
|
||||
# The change author gets credit for the edit.
|
||||
# The person who committed or merged to the approval branch gets credit for approval.
|
||||
approvedBranch: master
|
||||
tickets:
|
||||
github:
|
||||
token: XXXX
|
||||
token: XXX
|
||||
username: strongdm
|
||||
repo: comply
|
||||
repo: comply
|
||||
# jira:
|
||||
# username: xxxx # This is the username you log in to Jira's UI with. Probably your email address.
|
||||
# password: xxxx # If you don't have a "managed account", use your password in this field. But if your organization
|
||||
# # uses SAML or OAuth, or Jira's built-in multi-factor authentication, you need to use
|
||||
# # an API token. Learn more here: https://confluence.atlassian.com/cloud/api-tokens-938839638.html
|
||||
# project: comply
|
||||
# url: https://yourjira
|
||||
# taskType: Task # This must be an Issue, not a sub-task
|
||||
# gitlab:
|
||||
# domain: https://gitlab.example.com:443/ # or https://gitlab.com/
|
||||
# token: token-here
|
||||
# repo: full-slug/of-project
|
||||
|
@ -0,0 +1,3 @@
|
||||
# Narratives
|
||||
|
||||
Narratives provide an overview of the organization and the compliance environment.
|
@ -17,4 +17,78 @@ majorRevisions:
|
||||
|
||||
# Control Environment Narrative
|
||||
|
||||
Here we narrate why our org satisfies the control keys listed in the YML block
|
||||
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.
|
@ -9,7 +9,6 @@ satisfies:
|
||||
- CC3.1
|
||||
- CC3.2
|
||||
- CC3.3
|
||||
- CC3.4
|
||||
majorRevisions:
|
||||
- date: Jun 1 2018
|
||||
comment: Initial document
|
||||
@ -17,4 +16,57 @@ majorRevisions:
|
||||
|
||||
# Organizational Narrative
|
||||
|
||||
Here we narrate why our org satisfies the control keys listed in the YML block
|
||||
The following provides a description of the corporate a management structure of {{.Name}}.
|
||||
|
||||
The intent of this description is to establish both the legal jurisdiction and corporate cultural norms that serve as the foundation for {{.Name}}'s compliance program.
|
||||
|
||||
# Entity Type
|
||||
|
||||
{{.Name}} is a Delaware C-Corporation headquartered in San Francisco, California. {{.Name}} was established in 1970.
|
||||
|
||||
# Integrity and Ethics
|
||||
|
||||
The Directors and Executives of {{.Name}} aspire to and demonstrate standards of ethics and integrity consistent with professional norms in American corporate environments.
|
||||
|
||||
Chief among these standards is a commitment to honesty in interactions with and among managers, directors, employees, contractors, customers, and other stakeholders.
|
||||
|
||||
# Board Independence
|
||||
|
||||
The Board of Directors appoints and oversees the Chief Executive Officer (CEO).
|
||||
|
||||
# Organizational Structure
|
||||
|
||||
{{.Name}} is composed of 7 primary divisions:
|
||||
|
||||
* Sales
|
||||
* Marketing
|
||||
* Manufacturing
|
||||
* Research & Development
|
||||
* Information Technology
|
||||
* Human Resources
|
||||
* Finance
|
||||
|
||||
Each division is led by a Vice President, who in turn reports to the CEO. A complete Organization Chart is maintained and distributed by Human Resources.
|
||||
|
||||
# Management Objectives
|
||||
|
||||
Work is distributed to each division via Objectives set by the respective division Vice President, in collaboration with the Chief Executive Officer.
|
||||
|
||||
# Risk to Objectives
|
||||
|
||||
{{.Name}} seeks to manage risk to Objectives through professional management strategies and tactics, including:
|
||||
|
||||
* Rigorous hiring practices
|
||||
* Employee performance reviews
|
||||
* Aligning compensation with objectives
|
||||
* Regular communication of objectives by executive management
|
||||
|
||||
# Fraud Risk to Objectives
|
||||
|
||||
{{.Name}} acknowledges the possibility that fraud may imperil corporate objectives. {{.Name}} undertakes various activities to manage fraud risk, including:
|
||||
|
||||
* Conducting regular financial audits
|
||||
* Adhering to financial control principles
|
||||
* Investigating suspicious transactions
|
||||
* Performing criminal background checks on all employees
|
||||
* Maximizing the use of information technology in fraud detection
|
@ -1,8 +1,5 @@
|
||||
name: Products and Services Narrative
|
||||
acronym: PSN
|
||||
satisfies:
|
||||
TSC:
|
||||
- CC9.9
|
||||
majorRevisions:
|
||||
- date: Jun 1 2018
|
||||
comment: Initial document
|
||||
@ -10,4 +7,41 @@ majorRevisions:
|
||||
|
||||
# Products Narrative
|
||||
|
||||
Here we describe the key products marketed by our organization
|
||||
Here we describe the key products marketed by our organization
|
||||
|
||||
# Products
|
||||
|
||||
## Product 1
|
||||
|
||||
Overview of product 1
|
||||
|
||||
### Architecture
|
||||
|
||||
Brief architectural discussion of product 1
|
||||
|
||||
### Security Considerations
|
||||
|
||||
Specific security considerations for product 1. Refer to policies, procedures here.
|
||||
|
||||
# References
|
||||
|
||||
## Narratives
|
||||
|
||||
List relevant narratives, probably including
|
||||
Organizational Narrative
|
||||
Security Narrative
|
||||
System Narrative
|
||||
|
||||
## Policies
|
||||
|
||||
List relevant policies, probably including
|
||||
Application Security Policy
|
||||
Datacenter Policy
|
||||
Log Management Policy
|
||||
Password Policy
|
||||
Security Incident Response Policy
|
||||
Risk Assessment Policy
|
||||
|
||||
## Procedures
|
||||
|
||||
List relevant procedures, probably including access review, patching, alert monitoring, log review, pen testing
|
@ -11,6 +11,103 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Control Environment Narrative
|
||||
# Security Architecture Narrative
|
||||
|
||||
Here we narrate why our org satisfies the control keys listed in the YML block
|
||||
Here we narrate why our org satisfies the control keys listed in the YML block
|
||||
|
||||
# {{.Name}} Product Architecture
|
||||
|
||||
Describe product architecture here, emphasizing security implications
|
||||
|
||||
# {{.Name}} Infrastructure
|
||||
|
||||
## Product Infrastructure
|
||||
|
||||
Describe product infrastructure, emphasizing security measures
|
||||
|
||||
### Authorized Personnel
|
||||
|
||||
- **AWS root account** access is granted only to the CTO and CEO
|
||||
- **AWS IAM** access is granted to to a limited group of **Operators**
|
||||
- **{{.Name}} SSH** access is granted to a limited group of **Operators**
|
||||
- **{{.Name}} DB** access is granted to a limited group of **Data Operators**
|
||||
|
||||
## IT Infrastructure
|
||||
|
||||
{{.Name}} uses the following cloud services for its internal infrastructure:
|
||||
|
||||
- List cloud services
|
||||
|
||||
Access to these cloud services is limited according to the role of the {{.Name}} employee and is reviewed quarterly as well as via regular onboarding/offboarding tasks for new and departing employees.
|
||||
|
||||
# {{.Name}} Workstations
|
||||
|
||||
{{.Name}} workstations are hardened against logical and physical attack by the following measures:
|
||||
|
||||
- operating system must be within one generation of current
|
||||
- full-disk encryption
|
||||
- onboard antivirus/antimalware software
|
||||
- OS and AV automatically updated
|
||||
|
||||
Workstation compliance with these measures is evaluated on a quarterly basis.
|
||||
|
||||
## Remote Access
|
||||
|
||||
Many {{.Name}} employees work remotely on a regular basis and connect to production and internal IT systems via the same methods as those employees connecting from the {{.Name}} physical office, i.e., direct encrypted access to cloud services. It is the employee's responsibility to ensure that only authorized personnel use {{.Name}} resources and access {{.Name}} systems.
|
||||
|
||||
# Access Review
|
||||
|
||||
Access to {{.Name}} infrastructure, both internal and product, is reviewed quarterly and inactive users are removed. Any anomalies are reported to the security team for further investigation. When employees start or depart, an onboarding/offboarding procedure is followed to provision or deprovision appropriate account access.
|
||||
|
||||
# Penetration Testing
|
||||
|
||||
{{.Name}} commissions an external penetration test on an annual basis. All findings are immediately reviewed and addressed to the satisfaction of the CTO/CEO.
|
||||
|
||||
# {{.Name}} Physical Security
|
||||
|
||||
{{.Name}} has one physical location, in San Francisco, CA. Key issuance is tracked by the Office Physical Security Policy Ledger. Office keys are additionally held by the lessor, property management, and custodial staff. These keys are not tracked by the Office Physical Security Policy Ledger. {{.Name}} managers regularly review physical access privileges.
|
||||
|
||||
{{.Name}} infrastructure is located within AWS. {{.Name}} does not have physical access to AWS infrastructure.
|
||||
|
||||
# Risk Assessment
|
||||
|
||||
{{.Name}} updates its Cyber Risk Assessment on an annual basis in order to keep pace with the evolving threat landscape. The following is an inventory of adversarial and non-adversarial threats assessed to be of importance to {{.Name}}.
|
||||
|
||||
## Adversarial Threats
|
||||
|
||||
The following represents the inventory of adversarial threats:
|
||||
|
||||
|Threat|Source|Vector|Target|Likelihood|Severity|
|
||||
|----------------------------+--------------+------------+-----------------+----------+------|
|
||||
| | | | | | |
|
||||
|
||||
## Non-Adversarial Threats
|
||||
|
||||
The following represents the inventory of non-adversarial threats:
|
||||
|
||||
|Threat|Vector|Target|Likelihood|Severity|
|
||||
|----------------------------+--------------+-------------+----------+------|
|
||||
| | | | | |
|
||||
|
||||
# References
|
||||
|
||||
## Narratives
|
||||
|
||||
Products and Services Narrative
|
||||
System Architecture Narrative
|
||||
|
||||
## Policies
|
||||
|
||||
Encryption Policy
|
||||
Log Management Policy
|
||||
Office Security Policy
|
||||
Remote Access Policy
|
||||
Security Incident Response Policy
|
||||
Workstation Policy
|
||||
|
||||
## Procedures
|
||||
|
||||
Apply OS Patches
|
||||
Review & Clear Low-Priority Alerts
|
||||
Review Access
|
||||
Review Devices & Workstations
|
||||
|
@ -1,10 +1,12 @@
|
||||
name: System Architecture Narrative
|
||||
acronym: SYN
|
||||
acronym: SAN
|
||||
majorRevisions:
|
||||
- date: Jun 1 2018
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Control Environment Narrative
|
||||
# System Architecture Narrative
|
||||
|
||||
Here we narrate why our org satisfies the control keys listed in the YML block
|
||||
|
||||
# Template Coming Soon
|
||||
|
@ -1 +1,3 @@
|
||||
# TODO Describe Policies
|
||||
# Policies
|
||||
|
||||
Policies govern the behavior of employees and contractors.
|
||||
|
@ -9,7 +9,49 @@ majorRevisions:
|
||||
- date: Jun 1 2018
|
||||
comment: Initial document
|
||||
---
|
||||
# Purpose and Scope
|
||||
|
||||
a. The purpose of this policy 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 person’s job duties. When a user’s 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.
|
||||
|
||||
# Overview
|
||||
|
||||
The XXX Policy governs X.
|
||||
|
@ -8,26 +8,111 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The Application Security Policy governs the use of applications deemed critical to {{.Name} Information Security.
|
||||
a. This application security policy defines the security framework and requirements for applications, notably web applications, within the organization’s production environment.
|
||||
|
||||
# Critical Applications
|
||||
a. This document also provides implementing controls and instructions for web application security, to include periodic vulnerability scans and other types of evaluations and assessments.
|
||||
|
||||
The following applications are within the scope of this policy:
|
||||
a. This policy applies to all applications within the organization’ production environment, as well as administrators and users of these applications. This typically includes employees and contractors.
|
||||
|
||||
* GitHub
|
||||
* Slack
|
||||
* Google Apps
|
||||
# Background
|
||||
|
||||
Applications supporting production data operations (specifically the AWS Console) are deliberately excluded from this policy.
|
||||
a. Application vulnerabilities typically account for the largest number of initial attack vectors after malware infections. As a result, it is important that applications are designed with security in mind, and that they are scanned and continuously monitored for malicious activity that could indicate a system compromise. Discovery and subsequent mitigation of application vulnerabilities will limit the organization’s attack surface, and ensures a baseline level of security across all systems.
|
||||
|
||||
# Data Sensitivity
|
||||
a. In addition to scanning guidance, this policy also defines technical requirements and procedures to ensure that applications are properly hardened in accordance with security best practices.
|
||||
|
||||
Any company proprietary data may be stored within these *[Critical Applications]*.
|
||||
# References
|
||||
|
||||
Customer support activities must be conducted entirely within the *[Critical Applications]*.
|
||||
a. Data Classification Policy
|
||||
|
||||
# Other Applications
|
||||
a. OWASP Risk Rating Methodology
|
||||
|
||||
a. OWASP Testing Guide
|
||||
|
||||
a. OWASP Top Ten Project
|
||||
|
||||
# Policy
|
||||
|
||||
a. The organization must ensure that all applications it develops and/or acquires are securely configured and managed.
|
||||
|
||||
a. The following security best practices must be considered and, if feasible, applied as a matter of the application’s security design:
|
||||
|
||||
i. Data handled and managed by the application must be classified in accordance with the Data Classification Policy (reference (a)).
|
||||
|
||||
i. If the application processes confidential information, a confidential record banner must be prominently displayed which highlights the type of confidential data being accessed (e.g., personally-identifiable information (PII), protected health information (PHI), etc.)
|
||||
|
||||
i. Sensitive data, especially data specifically restricted by law or policy (e.g., social security numbers, passwords, and credit card data) should not be displayed in plaintext.
|
||||
|
||||
i. Ensure that applications validate input properly and restrictively, allowing only those types of input that are known to be correct. Examples include, but are not limited to cross-site scripting, buffer overflow errors, and injection flaws.
|
||||
|
||||
i. Ensure that applications execute proper error handling so that errors will not provide detailed system information to an unprivileged user, deny service, impair security mechanisms, or crash the system.
|
||||
|
||||
i. Where possible, authorize access to applications by affiliation, membership or employment, rather than by individual. Provide an automated review of authorizations on a regular basis, where possible.
|
||||
|
||||
i. Ensure that applications encrypt data at rest and in transit.
|
||||
|
||||
i. Implement application logging to the extent practical. Retain logs of all users and access events for at least 14 days.
|
||||
|
||||
i. Qualified peers conduct security reviews of code for all new or significantly modified applications; particularly, those that affect the collection, use, and/or display of confidential data. Document all actions taken.
|
||||
|
||||
i. Implement a change management process for changes to existing software applications.
|
||||
|
||||
i. Standard configuration of the application must be documented.
|
||||
|
||||
i. Default passwords used within the application, such as for administrative control panels or integration with databases must be changed immediately upon installation.
|
||||
|
||||
i. Applications must require complex passwords in accordance with current security best practices (at least 8 characters in length, combination of alphanumeric upper/lowercase characters and symbols).
|
||||
|
||||
i. During development and testing, applications must not have access to live data.
|
||||
|
||||
a. Where applications are acquired from a third party, such as a vendor:
|
||||
|
||||
i. Only applications that are supported by an approved vendor shall be procured and used.
|
||||
|
||||
i. Full support contracts must be arranged with the application vendor for full life-cycle support.
|
||||
|
||||
i. No custom modifications may be applied to the application without confirmation that the vendor can continue to provide support.
|
||||
|
||||
i. Updates, patches and configuration changes issued by the vendor shall be implemented as soon as possible.
|
||||
|
||||
i. A full review of applications and licenses shall be completed at least annually, as part of regular software reviews.
|
||||
|
||||
a. Web applications must be assessed according to the following criteria:
|
||||
|
||||
i. New or major application releases must have a full assessment prior to approval of the change control documentation and/or release into the production environment.
|
||||
|
||||
i. Third-party or acquired applications must have a full assessment prior to deployment.
|
||||
|
||||
i. Software releases must have an appropriate assessment, as determined by the organization’s information security manager, with specific evaluation criteria based on the security risks inherent in the changes made to the application’s functionality and/or architecture.
|
||||
|
||||
i. Emergency releases may forego security assessments and carry the assumed risk until a proper assessment can be conducted. Emergency releases must be approved by the Chief Information Officer or designee.
|
||||
|
||||
a. Vulnerabilities that are discovered during application assessments must be mitigated based upon the following risk levels, which are based on the Open Web Application Security Project (OWASP) Risk Rating Methodology (reference (b)):
|
||||
|
||||
i. High - issues categorized as high risk must be fixed immediately, otherwise alternate mitigation strategies must be implemented to limit exposure before deployment. Applications with high risk issues are subject to being taken off-line or denied release into the production environment.
|
||||
|
||||
i. Medium - issues categorized as medium risk must be reviewed to determine specific items to be mitigated. Actions to implement mitigations must be scheduled. Applications with medium risk issues may be taken off-line or denied release into the production environment based on the number of issues; multiple issues may increase the risk to an unacceptable level. Issues may be fixed in patch releases unless better mitigation options are present.
|
||||
|
||||
i. Low - issues categorized as low risk must be reviewed to determine specific items to be mitigated. Actions to implement mitigations must be scheduled.
|
||||
|
||||
a. Testing is required to validate fixes and/or mitigation strategies for any security vulnerabilities classified as Medium risk or greater.
|
||||
|
||||
a. The following security assessment types may be leveraged to perform an application security assessment:
|
||||
|
||||
i. Full - comprised of tests for all known web application vulnerabilities using both automated and manual tools based on the OWASP Testing Guide (reference (c)). A full assessment must leverage manual penetration testing techniques to validate discovered vulnerabilities to determine the overall risk of any and all discovered issues.
|
||||
|
||||
i. Quick - consists of an automated scan of an application for, at a minimum, the OWASP Top Ten web application security risks (reference (d)).
|
||||
|
||||
i. Targeted - verifies vulnerability remediation changes or new application functionality.
|
||||
|
||||
i. To counter the risk of unauthorized access, the organization maintains a Data Center Security Policy (reference (c)).
|
||||
|
||||
i. Security requirements for the software development life cycle, including system development, acquisition and maintenance are defined in the Software Development Lifecycle Policy (reference (d)).
|
||||
|
||||
i. Security requirements for handling information security incidents are defined in the Security Incident Response Policy (reference (e)).
|
||||
|
||||
i. Disaster recovery and business continuity management policy is defined in the Disaster Recovery Policy (reference (f)).
|
||||
|
||||
i. Requirements for information system availability and redundancy are defined in the System Availability Policy (reference (g)).
|
||||
|
||||
Other applications not listed in *[Critical Applications]* may include company proprietary data, but must not contain any customer support or customer-owned data.
|
@ -9,6 +9,92 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The Availability Policy governs X.
|
||||
a. The purpose of this policy is to define requirements for proper controls to protect the availability of the organization’s information systems.
|
||||
|
||||
a. This policy applies to all users of information systems within the organization. This typically includes employees and contractors, as well as any external parties that come into contact with systems and information controlled by the organization (hereinafter referred to as “users”). This policy must be made readily available to all users.
|
||||
|
||||
# Background
|
||||
|
||||
a. The intent of this policy is to minimize the amount of unexpected or unplanned downtime (also known as outages) of information systems under the organization’s control. This policy prescribes specific measures for the organization that will increase system redundancy, introduce failover mechanisms, and implement monitoring such that outages are prevented as much as possible. Where they cannot be prevented, outages will be quickly detected and remediated.
|
||||
|
||||
a. Within this policy, an availability is defined as a characteristic of information or information systems in which such information or systems can be accessed by authorized entities whenever needed.
|
||||
|
||||
# References
|
||||
|
||||
a. Risk Assessment Policy
|
||||
|
||||
# Policy
|
||||
|
||||
a. Information systems must be consistently available to conduct and support business operations.
|
||||
|
||||
a. Information systems must have a defined availability classification, with appropriate controls enabled and incorporated into development and production processes based on this classification.
|
||||
|
||||
a. System and network failures must be reported promptly to the organization’s lead for Information Technology (IT) or designated IT operations manager.
|
||||
|
||||
a. Users must be notified of scheduled outages (e.g., system maintenance) that require periods of downtime. This notification must specify the date and time of the system maintenance, expected duration, and anticipated system or service resumption time.
|
||||
|
||||
a. Prior to production use, each new or significantly modified application must have a completed risk assessment that includes availability risks. Risk assessments must be completed in accordance with the Risk Assessment Policy (reference (a)).
|
||||
|
||||
a. Capacity management and load balancing techniques must be used, as deemed necessary, to help minimize the risk and impact of system failures.
|
||||
|
||||
a. Information systems must have an appropriate data backup plan that ensures:
|
||||
|
||||
i. All sensitive data can be restored within a reasonable time period.
|
||||
|
||||
i. Full backups of critical resources are performed on at least a weekly basis.
|
||||
|
||||
i. Incremental backups for critical resources are performed on at least a daily basis.
|
||||
|
||||
i. Backups and associated media are maintained for a minimum of thirty (30) days and retained for at least one (1) year, or in accordance with legal and regulatory requirements.
|
||||
|
||||
i. Backups are stored off-site with multiple points of redundancy and protected using encryption and key management.
|
||||
|
||||
i. Tests of backup data must be conducted once per quarter. Tests of configurations must be conducted twice per year.
|
||||
|
||||
a. Information systems must have an appropriate redundancy and failover plan that meets the following criteria:
|
||||
|
||||
i. Network infrastructure that supports critical resources must have system-level redundancy (including but not limited to a secondary power supply, backup disk-array, and secondary computing system). Critical core components (including but not limited to routers, switches, and other devices linked to Service Level Agreements (SLAs)) must have an actively maintained spare. SLAs must require parts replacement within twenty-four (24) hours.
|
||||
|
||||
i. Servers that support critical resources must have redundant power supplies and network interface cards. All servers must have an actively maintained spare. SLAs must require parts replacement within twenty-four (24) hours.
|
||||
|
||||
i. Servers classified as high availability must use disk mirroring.
|
||||
|
||||
a. Information systems must have an appropriate business continuity plan that meets the following criteria:
|
||||
|
||||
i. Recovery time and data loss limits are defined in Table 3.
|
||||
|
||||
i. Recovery time requirements and data loss limits must be adhered to with specific documentation in the plan.
|
||||
|
||||
i. Company and/or external critical resources, personnel, and necessary corrective actions must be specifically identified.
|
||||
|
||||
i. Specific responsibilities and tasks for responding to emergencies and resuming business operations must be included in the plan.
|
||||
|
||||
i. All applicable legal and regulatory requirements must be satisfied.
|
||||
|
||||
+-------------------+------------------+---------------+-------------------+------------------+
|
||||
|**Availability** | **Availability** | **Scheduled** | **Recovery Time** | **Data Loss or** |
|
||||
|**Classification** | **Requirements** | **Outage** | **Requirements** | **Impact Loss** |
|
||||
+===================+==================+===============+===================+==================+
|
||||
| High | High to | 30 minutes | 1 hour | Minimal |
|
||||
| | Continuous | | | |
|
||||
+-------------------+------------------+---------------+-------------------+------------------+
|
||||
| | | | | |
|
||||
+-------------------+------------------+---------------+-------------------+------------------+
|
||||
| Medium | Standard | 2 hours | 4 hours | Some data loss |
|
||||
| | Availability | | | is tolerated if |
|
||||
| | | | | it results in |
|
||||
| | | | | quicker |
|
||||
| | | | | restoration |
|
||||
+-------------------+------------------+---------------+-------------------+------------------+
|
||||
| | | | | |
|
||||
+-------------------+------------------+---------------+-------------------+------------------+
|
||||
| Low | Limited | 4 hours | Next | Some data loss |
|
||||
| | Availability | | business day | is tolerated if |
|
||||
| | | | | it results in |
|
||||
| | | | | quicker |
|
||||
| | | | | restoration |
|
||||
+-------------------+------------------+---------------+-------------------+------------------+
|
||||
|
||||
Table 3: Recovery Time and Data Loss Limits
|
||||
|
@ -3,11 +3,49 @@ acronym: SCP
|
||||
satisfies:
|
||||
TSC:
|
||||
- CC8.1
|
||||
- CC3.4
|
||||
majorRevisions:
|
||||
- date: Jun 1 2018
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
a. This information security policy defines how changes to information systems are planned and implemented
|
||||
|
||||
a. This policy applies to the entire information security program at the organization (i.e. to all information and communications technology, as well as related documentation).
|
||||
|
||||
a. All employees, contractors, part-time and temporary workers, service providers, and those employed by others to perform work for the organization, or who have been granted to the organization’s information and communications technology, must comply with this policy.
|
||||
|
||||
# Background
|
||||
|
||||
a. This policy defines specific requirements to ensure that changes to systems and applications are properly planned, evaluated, reviewed, approved, communicated, implemented, documented, and reviewed, thereby ensuring the greatest probability of success. Where changes are not successful, this document provides mechanisms for conducting post-implementation review such that future mistakes and errors can be prevented.
|
||||
|
||||
# Policy
|
||||
|
||||
a. Any changes to the security architecture or customer data handling of a system must be formally requested in writing to the organization’s Information Security Manager (ISM), and approved by the ISM and the Chief Information Officer (CIO).
|
||||
|
||||
a. All change requests must be documented.
|
||||
|
||||
a. All change requests must be prioritized in terms of benefits, urgency, effort required, and potential impacts to the organization’s operations.
|
||||
|
||||
a. All implemented changes must be communicated to relevant users.
|
||||
|
||||
a. Change management must be conducted according to the following procedure:
|
||||
|
||||
i. *Planning*: plan the change, including the implementation design, scheduling, and implementation of a communications plan, testing plan, and roll-back plan.
|
||||
|
||||
i. *Evaluation*: evaluate the change, including priority level of the service and risk that the proposed change introduces to the system; determine the change type and the specific step-by-step process to implement the change.
|
||||
|
||||
i. *Review*: review the change plan amongst the CIO, ISM, Engineering Lead, and, if applicable, Business Unit Manager.
|
||||
|
||||
i. *Approval*: the CIO must approve the change plan.
|
||||
|
||||
i. *Communication*: communicate the change to all users of the system.
|
||||
|
||||
i. *Implementation*: test and implement the change.
|
||||
|
||||
i. *Documentation*: record the change and any post-implementation issues.
|
||||
|
||||
i. *Post-change review*: conduct a post-implementation review to determine how the change is impacting the organization, either positively or negatively. Discuss and document any lessons learned.
|
||||
|
||||
The XXX Policy governs X.
|
||||
|
@ -7,31 +7,279 @@ majorRevisions:
|
||||
- date: Jun 1 2018
|
||||
comment: Initial document
|
||||
---
|
||||
# Appendices
|
||||
|
||||
# Background
|
||||
Appendix A: Handling of Classified Information
|
||||
|
||||
This policy defines the high level objectives and implementation instructions for the organization’s data classification scheme. This includes data classification levels, as well as procedures for the classification, labeling and handling of data within the organization. Confidentiality and non-disclosure agreements maintained by the organization must reference this policy.
|
||||
Appendix B: Form - Confidentiality Statement
|
||||
|
||||
# Purpose and Scope
|
||||
|
||||
- This data classification policy defines the requirements to ensure that information within the organization is protected at an appropriate level.
|
||||
a. This data classification policy defines the requirements to ensure that information within the organization is protected at an appropriate level.
|
||||
|
||||
- This document applies to the entire scope of the organization’s information security program. It includes all types of information, regardless of its form, such as paper or electronic documents, applications and databases, and knowledge or information that is not written.
|
||||
a. This document applies to the entire scope of the organization’s information security program. It includes all types of information, regardless of its form, such as paper or electronic documents, applications and databases, and knowledge or information that is not written.
|
||||
|
||||
- This policy applies to all individuals and systems that have access to information kept by the organization.
|
||||
a. This policy applies to all individuals and systems that have access to information kept by the organization.
|
||||
|
||||
# Background
|
||||
|
||||
a. This policy defines the high level objectives and implementation instructions for the organization’s data classification scheme. This includes data classification levels, as well as procedures for the classification, labeling and handling of data within the organization. Confidentiality and non-disclosure agreements maintained by the organization must reference this policy.
|
||||
|
||||
# References
|
||||
|
||||
- Risk Assessment Policy
|
||||
- Security Incident Management Policy
|
||||
a. Risk Assessment Policy
|
||||
|
||||
a. Security Incident Management Policy
|
||||
|
||||
# Policy
|
||||
|
||||
- If classified information is received from outside the organization, the person who receives the information must classify it in accordance with the rules prescribed in this policy. The person thereby will become the owner of the information.
|
||||
- If classified information is received from outside the organization and handled as part of business operations activities (e.g., customer data on provided cloud services), the information classification, as well as the owner of such information, must be made in accordance with the specifications of the respective customer service agreement and other legal requirements.
|
||||
- When classifying information, the level of confidentiality is determined by:
|
||||
- The value of the information, based on impacts identified during the risk assessment process. More information on risk assessments is defined in the Risk Assessment Policy (reference (a)).
|
||||
- Sensitivity and criticality of the information, based on the highest risk calculated for each information item during the risk assessment.
|
||||
- Legal, regulatory and contractual obligations.
|
||||
a. If classified information is received from outside the organization, the person who receives the information must classify it in accordance with the rules prescribed in this policy. The person thereby will become the owner of the information.
|
||||
|
||||
a. If classified information is received from outside the organization and handled as part of business operations activities (e.g., customer data on provided cloud services), the information classification, as well as the owner of such information, must be made in accordance with the specifications of the respective customer service agreement and other legal requirements.
|
||||
|
||||
a. When classifying information, the level of confidentiality is determined by:
|
||||
|
||||
i. The value of the information, based on impacts identified during the risk assessment process. More information on risk assessments is defined in the Risk Assessment Policy (reference (a)).
|
||||
|
||||
i. Sensitivity and criticality of the information, based on the highest risk calculated for each information item during the risk assessment.
|
||||
|
||||
i. Legal, regulatory and contractual obligations.
|
||||
|
||||
|
||||
+-------------------+------------------+---------------------------+---------------------------+
|
||||
|**Confidentiality**| **Label** | **Classification** | **Access** |
|
||||
| **Level** | | **Criteria** | **Restrictions** |
|
||||
+===================+==================+===========================+============================+
|
||||
| Public | For Public | Making the information | Information is available |
|
||||
| | Release | public will not harm | to the public. |
|
||||
| | | the organization in | |
|
||||
| | | any way. | |
|
||||
+-------------------+------------------+---------------------------+---------------------------+
|
||||
| | | | |
|
||||
+-------------------+------------------+---------------------------+---------------------------+
|
||||
| Internal Use | Internal Use | Unauthorized access | Information is available |
|
||||
| | | may cause minor damage | to all employees and |
|
||||
| | | and/or inconvenience | authorized third parties. |
|
||||
| | | to the organization. |
|
||||
+-------------------+------------------+---------------------------+---------------------------+
|
||||
| | | | |
|
||||
+-------------------+------------------+---------------------------+---------------------------+
|
||||
| Restricted | Restricted | Unauthorized access to | Information is available |
|
||||
| | | information may cause | to a specific group of |
|
||||
| | | considerable damage to | employees and authhorized |
|
||||
| | | the business and/or | third parties. |
|
||||
| | | the organization's | |
|
||||
| | | reputation. | |
|
||||
+-------------------+------------------+---------------------------+---------------------------+
|
||||
| | | | |
|
||||
+-------------------+------------------+---------------------------+---------------------------+
|
||||
| Confidential |Confidential | Unauthorized access to | Information is available |
|
||||
| | | information may cause | only to specific indivi- |
|
||||
| | | catastrophic damage to | duals in the |
|
||||
| | | business and/or the | organization. |
|
||||
| | | organization's reputation.| |
|
||||
+-------------------+------------------+---------------------------+---------------------------+
|
||||
|
||||
Table 3: Information Confidentiality Levels
|
||||
|
||||
|
||||
|
||||
d. Information must be classified based on confidentiality levels as defined in Table 3.
|
||||
|
||||
e. Information and information system owners should try to use the lowest confidentiality level that ensures an adequate level of protection, thereby avoiding unnecessary production costs.
|
||||
|
||||
f. Information classified as “Restricted” or “Confidential” must be accompanied by a list of authorized persons in which the information owner specifies the names or job functions of persons who have the right to access that information.
|
||||
|
||||
g. Information classified as “Internal Use” must be accompanied by a list of authorized persons only if individuals outside the organization will have access to the document.
|
||||
|
||||
h. Information and information system owners must review the confidentiality level of their information assets every five years and assess whether the confidentiality level should be changed. Wherever possible, confidentiality levels should be lowered.
|
||||
|
||||
a. For cloud-based software services provided to customers, system owners under the company’s control must also review the confidentiality level of their information systems after service agreement changes or after a customer’s formal notification. Where allowed by service agreements, confidentiality levels should be lowered.
|
||||
|
||||
a. Information must be labeled according to the following:
|
||||
|
||||
i. Paper documents: the confidentiality level is indicated on the top and bottom of each document page; it is also indicated on the front of the cover or envelope carrying such a document as well as on the filing folder in which the document is stored. If a document is not labeled, its default classification is Internal Use.
|
||||
|
||||
i. Electronic documents: the confidentiality level is indicated on the top and bottom of each document page. If a document is not labeled, its default classification is Internal Use.
|
||||
|
||||
i. Information systems: the confidentiality level in applications and databases must be indicated on the system access screen, as well as on the screen when displaying such information.
|
||||
|
||||
i. Electronic mail: the confidentiality level is indicated in the first line of the email body. If it is not labeled, its default classification is “Internal Use”.
|
||||
|
||||
i. Electronic storage media (disks, memory cards, etc.): the confidentiality level must be indicated on the top surface of the media. If it is not labeled, its default classification is “Internal Use”.
|
||||
|
||||
i. Information transmitted orally: the confidentiality level should be mentioned before discussing information during face-to-face communication, by telephone, or any other means of oral communication.
|
||||
|
||||
a. All persons accessing classified information must follow the guidelines listed in Appendix A, “Handling of Classified Information.”
|
||||
|
||||
a. All persons accessing classified information must complete and submit a Confidentiality Statement to their immediate supervisor or company point-of-contact. A sample Confidentiality Statement is in Appendix B.
|
||||
|
||||
a. Incidents related to the improper handling of classified information must be reported in accordance with the Security Incident Management Policy (reference (b)).
|
||||
|
||||
\pagebreak
|
||||
|
||||
# Appendix A: Handling of Classified Information
|
||||
|
||||
Information and information systems must be handled according to the following guidelines*:
|
||||
|
||||
a. Paper Documents
|
||||
|
||||
i. Internal Use
|
||||
|
||||
1. Only authorized persons may have access.
|
||||
|
||||
1. If sent outside the organization, the document must be sent as registered mail.
|
||||
|
||||
1. Documents may only be kept in rooms without public access.
|
||||
|
||||
1. Documents must be removed expeditiously from printers and fax machines.
|
||||
|
||||
i. Restricted
|
||||
|
||||
1. The document must be stored in a locked cabinet.
|
||||
|
||||
1. Documents may be transferred within and outside the organization only in a closed envelope.
|
||||
|
||||
1. If sent outside the organization, the document must be mailed with a return receipt service.
|
||||
|
||||
1. Documents must immediately be removed from printers and fax machines.
|
||||
|
||||
1. Only the document owner may copy the document.
|
||||
|
||||
1. Only the document owner may destroy the document.
|
||||
|
||||
i. Confidential
|
||||
|
||||
1. The document must be stored in a safe.
|
||||
|
||||
1. The document may be transferred within and outside the organization only by a trustworthy person in a closed and sealed envelope.
|
||||
|
||||
1. Faxing the document is not permitted.
|
||||
|
||||
1. The document may be printed only if the authorized person is standing next to the printer.
|
||||
|
||||
a. Electronic Documents
|
||||
|
||||
i. Internal Use
|
||||
|
||||
1. Only authorized persons may have access.
|
||||
|
||||
1. When documents are exchanged via unencrypted file sharing services such as FTP, they must be password protected.
|
||||
|
||||
1. Access to the information system where the document is stored must be protected by a strong password.
|
||||
|
||||
1. The screen on which the document is displayed must be automatically locked after 10 minutes of inactivity.
|
||||
|
||||
i. Restricted
|
||||
|
||||
1. Only persons with authorization for this document may access the part of the information system where this document is stored.
|
||||
|
||||
1. When documents are exchanged via file sharing services of any type, they must be encrypted.
|
||||
|
||||
1. Only the document owner may erase the document.
|
||||
|
||||
i. Confidential
|
||||
|
||||
1. The document must be stored in encrypted form.
|
||||
|
||||
1. The document may be stored only on servers which are controlled by the organization.
|
||||
|
||||
1. The document may only be shared via file sharing services that are encrypted such as HTTPS and SSH. Further, the document must be encrypted and protected with a string password when transferred.
|
||||
|
||||
a. Information Systems
|
||||
|
||||
i. Internal Use
|
||||
|
||||
1. Only authorized persons may have access.
|
||||
|
||||
1. Access to the information system must be protected by a strong password.
|
||||
|
||||
1. The screen must be automatically locked after 10 minutes of inactivity.
|
||||
|
||||
1. The information system may be only located in rooms with controlled physical access.
|
||||
|
||||
i. Restricted
|
||||
|
||||
1. Users must log out of the information system if they have temporarily or permanently left the workplace.
|
||||
|
||||
1. Data must be erased only with an algorithm that ensures secure deletion.
|
||||
|
||||
i. Confidential
|
||||
|
||||
1. Access to the information system must be controlled through multi-factor authentication (MFA).
|
||||
|
||||
1. The information system may only be installed on servers controlled by the organization.
|
||||
|
||||
1. The information system may only be located in rooms with controlled physical access and identity control of people accessing the room.
|
||||
|
||||
a. Electronic Mail
|
||||
|
||||
i. Internal Use
|
||||
|
||||
1. Only authorized persons may have access.
|
||||
|
||||
1. The sender must carefully check the recipient.
|
||||
|
||||
1. All rules stated under “information systems” apply.
|
||||
|
||||
i. Restricted
|
||||
|
||||
1. Email must be encrypted if sent outside the organization.
|
||||
|
||||
i. Confidential
|
||||
|
||||
1. Email must be encrypted.
|
||||
|
||||
a. Electronic Storage Media
|
||||
|
||||
i. Internal Use
|
||||
|
||||
1. Only authorized persons may have access.
|
||||
|
||||
1. Media or files must be password protected.
|
||||
|
||||
1. If sent outside the organization, the medium must be sent as registered mail.
|
||||
|
||||
1. The medium may only be kept in rooms with controlled physical access.
|
||||
|
||||
i. Restricted
|
||||
|
||||
1. Media and files must be encrypted.
|
||||
|
||||
1. Media must be stored in a locked cabinet.
|
||||
|
||||
1. If sent outside the organization, the medium must be mailed with a return receipt service.
|
||||
|
||||
1. Only the medium owner may erase or destroy the medium.
|
||||
|
||||
i. Confidential
|
||||
|
||||
1. Media must be stored in a safe.
|
||||
|
||||
1. Media may be transferred within and outside the organization only by a trustworthy person and in a closed and sealed envelope.
|
||||
|
||||
a. Information Transmitted Orally
|
||||
|
||||
i. Internal Use
|
||||
|
||||
1. Only authorized persons may have access to information.
|
||||
|
||||
1. Unauthorized persons must not be present in the room when the information is communicated.
|
||||
|
||||
i. Restricted
|
||||
|
||||
1. The room must be sound-proof.
|
||||
|
||||
1. The conversation must not be recorded.
|
||||
|
||||
i. Confidential
|
||||
|
||||
1. Conversation conducted through electronic means must be encrypted.
|
||||
|
||||
1. No transcript of the conversation may be kept.
|
||||
|
||||
In this document, controls are implemented cumulatively, meaning that controls for any confidentiality level imply the implementation of controls defined for lower confidentiality levels - if stricted controls are prescribed for a higher confidentiality level, then only such controls are implemented.
|
||||
|
||||
|
||||
|
||||
|
||||
- Information must be classified based on confidentiality levels as defined in Table 1.
|
@ -8,6 +8,89 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
a. The purpose of this policy is to define expected behavior from employees towards their colleagues, supervisors, and the overall organization.
|
||||
|
||||
a. We expect all employees to follow our Code of Conduct. Offensive behavior, disruptive behavior, and participation in serious disputes should be avoided. Employees are expected to foster a respectful and collaborative environment.
|
||||
|
||||
a. This policy applies to all employees and contractors. They are bound by their Employment Offer Letter or Independent Contractor Agreement to follow the Code of Conduct Policy while performing their duties. The Code of Conduct is outlined below:
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Compliance with law*
|
||||
|
||||
i. Employees should have an understanding of and comply with all environmental, safety, and fair dealing laws. When performing their job duty and dealing with the company’s products, finances, critical information, & public image, employees are expected to be ethical and responsible. If an employee is unsure of whether a contemplated action is permitted by law or Company policy, they should seek advice from the resource manager.
|
||||
|
||||
a. *Respect in the workplace*
|
||||
|
||||
i. Employees should respect their colleagues. Discriminatory behavior, harassment, or victimization will not be tolerated.
|
||||
|
||||
a. *Protection of company property*
|
||||
|
||||
i. Company property, both material or intangible, should be treated with respect and care. Employees and contractors:
|
||||
|
||||
1. Should not misuse company equipment
|
||||
|
||||
1. Should respect all intangible property, including trademarks, copyright, information, reports, and other property. These materials should be used only to complete job duties.
|
||||
|
||||
1. Should protect company facilities and other material property from damage and vandalism, whenever possible.
|
||||
|
||||
\pagebreak
|
||||
|
||||
a. *Personal appearance*
|
||||
|
||||
i. When in the workplace, employees must present themselves in an appropriate & professional manner. They should abide by the company dress code.
|
||||
|
||||
a. *Corruption*
|
||||
|
||||
i. Employees are discouraged from accepting gifts from clients or partners. Briberies are prohibited for the benefit of any external or internal party.
|
||||
|
||||
a. *Job duties and authority*
|
||||
|
||||
i. Employees should fulfill their job duties with integrity and respect towards all individuals involved.
|
||||
|
||||
i. Supervisors and managers may not use abuse their authority. Competency and workload should be taken into account when delegating duties to team members.
|
||||
|
||||
i. Team members are expected to follow their leaders’ instructions and complete their duties with thoughtfulness and in a timely manner.
|
||||
|
||||
a. *Absenteeism and tardiness*
|
||||
|
||||
i. Employees should be punctual when coming to and leaving from work and follow the schedule determined by their hiring manager. Exceptions can be made for occasions that prevent employees from following standard working hours or days, with approval from their hiring manager.
|
||||
|
||||
a. *Conflict of interest*
|
||||
|
||||
i. Employees should avoid any personal, financial, or other interests that might compete with their job duties.
|
||||
|
||||
a. *Collaboration*
|
||||
|
||||
i. Employees should be friendly with their colleagues and open to collaboration. They should not disrupt the workplace or present obstacles to their colleagues’ work.
|
||||
|
||||
a. *Communication*
|
||||
|
||||
i. Colleagues, supervisors, or team members must be open to communication amongst each other.
|
||||
|
||||
a. *Benefits*
|
||||
|
||||
i. We expect employees to not abuse their employment benefits. This can refer to time off, insurance, facilities, subscriptions, or other benefits our company offers. Refer to Human Resources for more information on benefits.
|
||||
|
||||
a. *Policies*
|
||||
|
||||
i. All employees must comply with company policies. Questions should be directed to their hiring managers and/or Human Resources.
|
||||
|
||||
a. *Disciplinary actions*
|
||||
|
||||
i. Repeated or intentional violation of the Code of Conduct Policy will be met with disciplinary action. Consequences will vary depending on the violation, but can include:
|
||||
|
||||
1. demotion
|
||||
1. reprimand
|
||||
1. suspension or termination
|
||||
1. detraction of benefits for a definite or indefinite time
|
||||
|
||||
ii. Cases of corruption, theft, embezzlement, or other unlawful behavior may call for legal action.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
The Data Classification Policy governs X.
|
||||
|
@ -9,6 +9,92 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
a. This policy outlines expected behavior of employees to keep confidential information about clients, partners, and our company secure.
|
||||
|
||||
a. This policy applies to all employees, board members, investors, and contractors, who may have access to confidential information. This policy must be made readily available to all whom it
|
||||
applies to.
|
||||
|
||||
# Background
|
||||
|
||||
a. The company's confidential information must be protected for two reasons:
|
||||
|
||||
i. It may be legally binding (i.e. sensitive customer data)
|
||||
|
||||
i. It may be fundamental to our business (i.e. business processes)
|
||||
|
||||
a. Common examples of confidential information in our company includes, but is not limited to:
|
||||
|
||||
i. Unpublished financial information
|
||||
|
||||
i. Customer/partner/vendor/external party data
|
||||
|
||||
i. Patents, formulas, new technologies, and other intellectual property
|
||||
|
||||
i. Existing and prospective customer lists
|
||||
|
||||
i. Undisclosed business strategies including pricing & marketing
|
||||
|
||||
i. Materials & processes explicitly marked as “confidential”
|
||||
|
||||
a. Employees will have varying levels of authorized access to confidential information.
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Employee procedure for handling confidential information*
|
||||
|
||||
i. Lock and secure confidential information at all times
|
||||
|
||||
i. Safely dispose (i.e. shred) documents when no longer needed
|
||||
|
||||
i. View confidential information only on secure devices
|
||||
|
||||
i. Disclose information only when authorized and necessary
|
||||
|
||||
i. Do not use confidential information for personal gain, benefit, or profit
|
||||
|
||||
i. Do not disclose confidential information to anyone outside the company or to anyone within the company who does not have appropriate privileges
|
||||
|
||||
i. Do not store confidential information or replicates of confidential information in unsecured manners (i.e. on unsecured devices)
|
||||
|
||||
i. Do not remove confidential documents from company's premises unless absolutely necessary to move
|
||||
|
||||
a. *Offboarding measures*
|
||||
|
||||
i. The Hiring Manager should confirm the off-boarding procedure has been completed by final date of employment.
|
||||
|
||||
a. *Confidentiality measures*
|
||||
|
||||
i. The company will take the following measures to ensure protection of confidential information:
|
||||
|
||||
1. Store and lock paper documents
|
||||
|
||||
1. Encrypt electronic information and implement appropriate technical measures to safeguard databases
|
||||
|
||||
1. Require employees to sign non-disclosure/non-compete agreements
|
||||
|
||||
1. Consult with senior management before granting employees access to certain confidential information
|
||||
|
||||
a. *Exceptions*
|
||||
|
||||
i. Under certain legitimate conditions, confidential information may need to be disclosed. Examples include:
|
||||
|
||||
1. If a regulatory agency requests information as part of an audit or investigation
|
||||
|
||||
1. If the company requires disclosing information (within legal bounds) as part of a venture or partnership
|
||||
|
||||
i. In such cases, employee must request and receive prior written authorization from their hiring manager before disclosing confidential information to any third parties.
|
||||
|
||||
a. *Disciplinary consequences*
|
||||
|
||||
i. Employees who violate the confidentiality policy will face disciplinary and possible legal action.
|
||||
|
||||
i. A suspected breach of this policy will trigger an investigation. Intentional violations will be met with termination and repeated unintentional violations may also face termination.
|
||||
|
||||
i. This policy is binding even after the termination of employment.
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -8,6 +8,89 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
The XXX Policy governs X.
|
||||
# Purpose and Scope
|
||||
|
||||
a. The purpose of this policy is to ensure that the organization establishes objectives, plans and, procedures such that a major disruption to the organization’s key business activities is minimized.
|
||||
|
||||
a. This policy applies to all infrastructure and data within the organization’s information security program.
|
||||
|
||||
a. This policy applies to all management, employees, and suppliers that are involved in decisions and processes affecting the organization’s business continuity. This policy must be made readily available to all whom it applies to.
|
||||
|
||||
# Background
|
||||
|
||||
a. The success of the organization is reliant upon the preservation of critical business operations and essential functions used to deliver key products and services. The purpose of this policy is to define the criteria for continuing business operations for the organization in the event of a disruption. Specifically, this document defines:
|
||||
|
||||
i. The structure and authority to ensure business resilience of key processes and systems.
|
||||
|
||||
i. The requirements for efforts to manage through a disaster or other disruptive event when the need arises.
|
||||
|
||||
i. The criteria to efficiently and effectively resume normal business operations after a disruption.
|
||||
|
||||
a. Within this document, the following definitions apply:
|
||||
|
||||
i. *Business impact analysis/assessment* - an exercise that determines the impact of losing the support of any resource to an enterprise, establishes the escalation of that loss over time, identifies the minimum resources needed to return to a normal level of operation, and prioritizes recovery of processes and the supporting system.
|
||||
|
||||
i. *Disaster recovery plan* - a set of human, physical, technical, and procedural resources to return to a normal level of operation, within a defined time and cost, when an activity is interrupted by an emergency or disaster.
|
||||
|
||||
i. *Recovery time objective* - the amount of time allowed for the recovery of a business function or resource to a normal level after a disaster or disruption occurs.
|
||||
|
||||
i. *Recovery point objective* - determined based on the acceptable data loss in the case of disruption of operations.
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Business Risk Assessment and Business Impact Analysis*
|
||||
|
||||
i. Each manager is required to perform a business risk assessment and business impact analysis for each key business system within their area of responsibility.
|
||||
|
||||
i. The business risk assessment must identify and define the criticality of key business systems and the repositories that contain the relevant and necessary data for the key business system.
|
||||
|
||||
i. The business risk assessment must define and document the Disaster Recovery Plan (DRP) for their area of responsibility. Each DRP shall include:
|
||||
|
||||
1. Key business processes.
|
||||
|
||||
1. Applicable risk to availability.
|
||||
|
||||
1. Prioritization of recovery.
|
||||
|
||||
1. Recovery Time Objectives (RTOs).
|
||||
|
||||
1. Recovery Point Objectives (RPOs).
|
||||
|
||||
a. *Disaster Recovery Plan*
|
||||
|
||||
i. Each key business system must have a documented DRP to provide guidance when hardware, software, or networks become critically dysfunctional or cease to function (short and long term outages).
|
||||
|
||||
i. Each DRP must include an explanation of the magnitude of information or system unavailability in the event of an outage and the process that would be implemented to continue business operations during the outage. Where feasible, the DRP must consider the use of alternative, off-site computer operations (cold, warm, hot sites).
|
||||
|
||||
i. Each plan must be reviewed against the organization’s strategy, objectives, culture, and ethics, as well as policy, legal, statutory and regulatory requirements.
|
||||
|
||||
i. Each DRP must include:
|
||||
|
||||
1. An emergency mode operations plan for continuing operations in the event of temporary hardware, software, or network outages.
|
||||
|
||||
1. A recovery plan for returning business functions and services to normal on-site operations.
|
||||
|
||||
1. Procedures for periodic testing, review, and revisions of the DRP for all affected business systems, as a group and/or individually.
|
||||
|
||||
a. *Data Backup and Restoration Plans*
|
||||
|
||||
i. Each system owner must implement a data backup and restoration plan.
|
||||
|
||||
i. Each data backup and restoration plan must identify:
|
||||
|
||||
1. The data custodian for the system.
|
||||
|
||||
|
||||
1. The backup schedule of each system.
|
||||
|
||||
|
||||
1. Where backup media is to be stored and secured, as well as how access is maintained.
|
||||
|
||||
1. Who may remove backup media and transfer it to storage.
|
||||
|
||||
1. Appropriate restoration procedures to restore key business system data from backup media to the system.
|
||||
|
||||
1. The restoration testing plan and frequency of testing to confirm the effectiveness of the plan.
|
||||
|
||||
1. The method for restoring encrypted backup media.
|
||||
|
@ -8,6 +8,61 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
a. The purpose of this policy is to define the procedures to assess and treat information security risks within the organization, and to define the acceptable level of risk overall.
|
||||
|
||||
a. Risk assessment and risk treatment are applied to the entire scope of the organization’s information security program, and to all information systems which are used within the organization or which could have an impact on the organization’s information security.
|
||||
|
||||
a. This policy applies to all management and employees that take part in the organization’s risk assessments. This policy must be made readily available to all whom it applies to.
|
||||
|
||||
# Background
|
||||
|
||||
a. This policy defines a step-by-step process for conducting risk assessments, as well as to treat identified risks from an information security perspective. This policy also describes how to prepare the Risk Assessment Report required as part of the risk assessment process.
|
||||
|
||||
a. When conducting a risk assessment, the organization must identify all organizational information systems . It must then identify all threats and vulnerabilities having to do with such systems , and rate the severity of such threats and vulnerabilities according to a predefined rating scale. Asset and risk owners must be defined for each risk item.
|
||||
|
||||
a. Once the risk assessment is completed, the organization shall determine how to manage risks where the overall assessed risk rating is deemed as too high. This management is known as risk treatment. Risk treatment options include but are not limited to applying security controls, outsourcing risk, accepting risk, or discontinuing the activity associated with the risk.
|
||||
|
||||
a. A penetration test must be performed by a third party to verify the accuracy of the risk assessment and effectiveness of deployed risk treatments.
|
||||
|
||||
# Procedure To Execute Risk Assessment Report
|
||||
|
||||
a. Confirms that the entire risk assessment and risk treatment process has been carried out according to the Risk Assessment Policy.
|
||||
|
||||
a. The purpose of the risk assessment was to identify all information systems their vulnerabilities, and threats that could exploit vulnerabilities. These parameters were further evaluated in order to establish the criticality of individual risks.
|
||||
|
||||
a. The purpose of the risk treatment was to define the systematic means of reducing or controlling the risks identified in the risk assessment.
|
||||
|
||||
a. All risk assessment and treatment activities were completed within the scope of the organization’s information security program.
|
||||
|
||||
a. The risk assessment was implemented in the period from [day/month/year] to [day/month/year]. The risk treatment was implemented from [day/month/year] to [day/month/year]. Final reports were prepared during [specify period].
|
||||
|
||||
a. The risk assessment and risk treatment process was managed by [person responsible for managing the risk assessment process] with expert assistance provided by [person or company responsible for assistance].
|
||||
|
||||
a. During the risk assessment, information was collected through questionnaires and interviews with responsible persons, namely the asset owners across organizational units.
|
||||
|
||||
a. The process was conducted as follows:
|
||||
|
||||
i. All information systems and their owners were identified.
|
||||
|
||||
i. Threats were identified for each asset, and corresponding vulnerabilities were identified for each threat.
|
||||
i. Risk owners were identified for each risk.
|
||||
|
||||
i. Consequences of the loss of confidentiality, integrity and availability were evaluated using a score from 0 to 2, with 0 being the lowest rating and 2 being the highest rating.
|
||||
|
||||
i. The likelihood of risk occurrence (i.e. that the threat will exploit the vulnerability) was evaluated using a score from 0 to 2, with 0 being the lowest rating and 2 being the highest rating.
|
||||
|
||||
i. The level of risk was calculated by adding up the consequence and likelihood.
|
||||
|
||||
i. Risks with a score of 3 or 4 were determined to be unacceptable risks.
|
||||
|
||||
i. For each unacceptable risk, a risk treatment option was considered, and appropriate information security controls were selected.
|
||||
|
||||
i. After controls were applied, residual risks were assessed.
|
||||
|
||||
a. The following documents were used or generated during the implementation of risk assessment and risk treatment:
|
||||
|
||||
i. Risk Assessment Table (Appendix A): for each combination of systems , vulnerabilities and threats, this table shows the values for consequence and likelihood, and calculates the risk.
|
||||
|
||||
i. Risk Treatment Table (Appendix B): defines the options for risk treatment, selection of controls for each unacceptable risk, and the level of residual risk.
|
@ -8,6 +8,52 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
a. The purpose of this policy is to define security procedures within the organization’s data centers and secure equipment areas.
|
||||
|
||||
a. This policy applies to any cloud hosted providers and facilities within the organization that are labeled as either a data center or a secure equipment area. Such facilities are explicitly called out within this document.
|
||||
|
||||
a. This policy applies to all management, employees and suppliers that conduct business operations within cloud host or data centers and secure equipment areas.
|
||||
|
||||
# Background
|
||||
|
||||
a. This policy defines the policies and rules governing data centers and secure equipment areas from both a physical and logical security perspective. The document lists all data centers and secure equipment areas in use by the organization, prescribes how access is controlled and enforced, and establishes procedures for any visitor or third party access. This policy also defines prohibited activities and requirements for periodic safety and security checks.
|
||||
|
||||
# Policy
|
||||
|
||||
a. The following locations are classified by the organization as secure areas and are goverened by this policy:
|
||||
|
||||
i. [list all data center locations and secure areas under the organization’s control]
|
||||
|
||||
a. Each data center and secure area must have a manager assigned. The manager’s name must be documented in the organization’s records. In the case of any on-prem data centers, the manager’s name must also be posted in and near the secure area.
|
||||
|
||||
a. Each secure area must be clearly marked. Access to the secure area must be controlled by at least a locked door. A visitor access log must be clearly marked and easily accessible just inside the door.
|
||||
|
||||
a. Persons who are not employed by the organization are considered to be visitors. Visitors accessing secure areas shall:
|
||||
|
||||
i. Obtain access to secure areas in accordance with reference a.
|
||||
|
||||
i. Only enter and remain in secure areas when escorted by a designated employee. The employee must stay with the visitor during their entire stay inside the secure area.
|
||||
|
||||
i. Log the precise time of entry and exit in the visitor access log.
|
||||
|
||||
a. The following activities are prohibited inside secure areas:
|
||||
|
||||
i. Photography, or video or audio recordings of any kind.
|
||||
|
||||
i. Connection of any electrical device to a power supply, unless specifically authorized by the responsible person.
|
||||
|
||||
i. Unauthorized usage of or tampering with any installed equipment.
|
||||
|
||||
i. Connection of any device to the network, unless specifically authorized by the responsible person.
|
||||
|
||||
i. Storage or archival of large amounts of paper materials.
|
||||
|
||||
i. Storage of flammable materials or equipment.
|
||||
|
||||
i. Use of portable heating devices.
|
||||
|
||||
i. Smoking, eating, or drinking.
|
||||
|
||||
a. Secure areas must be checked for compliance with security and safety requirements on at least a quarterly basis.
|
||||
|
@ -8,6 +8,188 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
a. The purpose of this policy is to define requirements for establishing and maintaining baseline protection standards for company software, network devices, servers, and desktops.
|
||||
|
||||
a. This policy applies to all users performing software development, system administration, and management of these activities within the organization. This typically includes employees and contractors, as well as any relevant external parties involved in these activities (hereinafter referred to as “users”). This policy must be made readily available to all users.
|
||||
|
||||
a. This policy also applies to enterprise-wide systems and applications developed by the organization or on behalf of the organization for production implementation.
|
||||
|
||||
# Background
|
||||
|
||||
a. The intent of this policy is to ensure a well-defined, secure and consistent process for managing the entire lifecycle of software and information systems, from initial requirements analysis until system decommission. The policy defines the procedure, roles, and responsibilities, for each stage of the software development lifecycle.
|
||||
|
||||
a. Within this policy, the software development lifecycle consists of requirements analysis, architecture and design, development, testing, deployment/implementation, operations/maintenance, and decommission. These processes may be followed in any form; in a waterfall model, it may be appropriate to follow the process linearly, while in an agile development model, the process can be repeated in an iterative fashion.
|
||||
|
||||
# References
|
||||
|
||||
a. Risk Assessment Policy
|
||||
|
||||
# Policy
|
||||
|
||||
a. The organization’s Software Development Life Cycle (SDLC) includes the following phases:
|
||||
|
||||
i. Requirements Analysis
|
||||
|
||||
i. Architecture and Design
|
||||
|
||||
i. Testing
|
||||
|
||||
i. Deployment/Implementation
|
||||
|
||||
i. Operations/Maintenance
|
||||
|
||||
i. Decommission
|
||||
|
||||
a. During all phases of the SDLC where a system is not in production, the system must not have live data sets that contain information identifying actual people or corporate entities, actual financial data such as account numbers, security codes, routing information, or any other financially identifying data. Information that would be considered sensitive must never be used outside of production environments.
|
||||
|
||||
a. The following activities must be completed and/or considered during the requirements analysis phase:
|
||||
|
||||
i. Analyze business requirements.
|
||||
|
||||
i. Perform a risk assessment. More information on risk assessments is discussed in the Risk Assessment Policy (reference (a)).
|
||||
|
||||
i. Discuss aspects of security (e.g., confidentiality, integrity, availability) and how they might apply to this requirement.
|
||||
|
||||
i. Review regulatory requirements and the organization’s policies, standards, procedures and guidelines.
|
||||
|
||||
i. Review future business goals.
|
||||
|
||||
i. Review current business and information technology operations.
|
||||
|
||||
i. Incorporate program management items, including:
|
||||
|
||||
1. Analysis of current system users/customers.
|
||||
|
||||
1. Understand customer-partner interface requirements (e.g., business-level, network).
|
||||
|
||||
1. Discuss project timeframe.
|
||||
|
||||
i. Develop and prioritize security solution requirements.
|
||||
|
||||
i. Assess cost and budget constraints for security solutions, including development and operations.
|
||||
|
||||
i. Approve security requirements and budget.
|
||||
|
||||
i. Make “buy vs. build” decisions for security services based on the information above.
|
||||
|
||||
a. The following must be completed/considered during the architecture and design phase:
|
||||
|
||||
i. Educate development teams on how to create a secure system.
|
||||
|
||||
i. Develop and/or refine infrastructure security architecture.
|
||||
|
||||
i. List technical and non-technical security controls.
|
||||
|
||||
i. Perform architecture walkthrough.
|
||||
|
||||
i. Create a system-level security design.
|
||||
|
||||
i. Create high-level non-technical and integrated technical security designs.
|
||||
|
||||
i. Perform a cost/benefit analysis for design components.
|
||||
|
||||
i. Document the detailed technical security design.
|
||||
|
||||
i. Perform a design review, which must include, at a minimum, technical reviews of application and infrastructure, as well as a review of high-level processes.
|
||||
|
||||
i. Describe detailed security processes and procedures, including: segregation of duties and segregation of development, testing and production environments.
|
||||
|
||||
i. Design initial end-user training and awareness programs.
|
||||
|
||||
i. Design a general security test plan.
|
||||
|
||||
i. Update the organization’s policies, standards, and procedures, if appropriate.
|
||||
|
||||
i. Assess and document how to mitigate residual application and infrastructure vulnerabilities.
|
||||
|
||||
i. Design and establish separate development and test environments.
|
||||
|
||||
a. The following must be completed and/or considered during the development phase:
|
||||
|
||||
i. Set up a secure development environment (e.g., servers, storage).
|
||||
|
||||
i. Train infrastructure teams on installation and configuration of applicable software, if required.
|
||||
|
||||
i. Develop code for application-level security components.
|
||||
|
||||
i. Install, configure and integrate the test infrastructure.
|
||||
|
||||
i. Set up security-related vulnerability tracking processes.
|
||||
|
||||
i. Develop a detailed security test plan for current and future versions (i.e., regression testing).
|
||||
|
||||
i. Conduct unit testing and integration testing.
|
||||
|
||||
a. The following must be completed and/or considered during the testing phase:
|
||||
|
||||
i. Perform a code and configuration review through both static and dynamic analysis of code to identify vulnerabilities.
|
||||
|
||||
i. Test configuration procedures.
|
||||
|
||||
i. Perform system tests.
|
||||
|
||||
i. Conduct performance and load tests with security controls enabled.
|
||||
|
||||
i. Perform usability testing of application security controls.
|
||||
|
||||
|
||||
i. Conduct independent vulnerability assessments of the system, including the infrastructure and application.
|
||||
|
||||
a. The following must be completed and/or considered during the deployment phase:
|
||||
|
||||
i. Conduct pilot deployment of the infrastructure, application and other relevant components.
|
||||
|
||||
i. Conduct transition between pilot and full-scale deployment.
|
||||
|
||||
i. Perform integrity checking on system files to ensure authenticity.
|
||||
|
||||
i. Deploy training and awareness programs to train administrative personnel and users in the system’s security functions.
|
||||
|
||||
i. Require participation of at least two developers in order to conduct full-scale deployment to the production environment.
|
||||
|
||||
a. The following must be completed and/or considered during the operations/maintenance phase:
|
||||
|
||||
i. Several security tasks and activities must be routinely performed to operate and administer the system, including but not limited to:
|
||||
|
||||
1. Administering users and access.
|
||||
|
||||
1. Tuning performance.
|
||||
|
||||
1. Performing backups according to requirements defined in the System Availability Policy
|
||||
|
||||
1. Performing system maintenance (i.e., testing and applying security updates and patches).
|
||||
|
||||
1. Conducting training and awareness.
|
||||
|
||||
1. Conducting periodic system vulnerability assessments.
|
||||
|
||||
1. Conducting annual risk assessments.
|
||||
|
||||
i. Operational systems must:
|
||||
|
||||
1. Be reviewed to ensure that the security controls, both automated and manual, are functioning correctly and effectively.
|
||||
|
||||
1. Have logs that are periodically reviewed to evaluate the security of the system and validate audit controls.
|
||||
|
||||
1. Implement ongoing monitoring of systems and users to ensure detection of security violations and unauthorized changes.
|
||||
|
||||
1. Validate the effectiveness of the implemented security controls through security training as required by the Procedure For Executing Incident Response.
|
||||
|
||||
1. Have a software application and/or hardware patching process that is performed regularly in order to eliminate software bug and security problems being introduced into the organization’s technology environment. Patches and updates must be applied within ninety (90) days of release to provide for adequate testing and propagation of software updates. Emergency, critical, break-fix, and zero-day vulnerability patch releases must be applied as quickly as possible.
|
||||
|
||||
a. The following must be completed and/or considered during the decommission phase:
|
||||
|
||||
i. Conduct unit testing and integration testing on the system after component removal.
|
||||
|
||||
i. Conduct operational transition for component removal/replacement.
|
||||
|
||||
i. Determine data retention requirements for application software and systems data.
|
||||
|
||||
i. Document the detailed technical security design.
|
||||
|
||||
i. Update the organization’s policies, standards and procedures, if appropriate.
|
||||
|
||||
i. Assess and document how to mitigate residual application and infrastructure vulnerabilities.
|
||||
|
||||
The XXX Policy governs X.
|
||||
|
@ -9,7 +9,144 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
s
|
||||
a. The purpose of this policy is to define the organization’s procedures to recover Information Technology (IT) infrastructure and IT services within set deadlines in the case of a disaster or other disruptive incident. The objective of this plan is to complete the recovery of IT infrastructure and IT services within a set Recovery Time Objective (RTO).
|
||||
|
||||
a. This policy includes all resources and processes necessary for service and data recovery, and covers all information security aspects of business continuity management.
|
||||
|
||||
a. This policy applies to all management, employees and suppliers that are involved in the recovery of IT infrastructure and services within the organization. This policy must be made readily available to all whom it applies to.
|
||||
|
||||
# Background
|
||||
|
||||
a. This policy defines the overall disaster recovery strategy for the organization. The strategy describes the organization’s Recovery Time Objective (RTO), which is defined as the duration of time and service level for critical business processes to be restored after a disaster or other disruptive event, as well as the procedures, responsibility and technical guidance required to meet the RTO. This policy also lists the contact information for personnel and service providers that may be needed during a disaster recovery event.
|
||||
|
||||
a. The following conditions must be met for this plan to be viable:
|
||||
|
||||
i. All equipment, software and data (or their backups/failovers) are available in some manner.
|
||||
|
||||
i. If an incident takes place at the organization’s physical location, all resources involved in recovery efforts are able to be transferred to an alternate work site (such as their home office) to complete their duties.
|
||||
|
||||
i. The Information Security Officer is responsible for coordinating and conducting a bi-annual (at least) rehearsal of this continuity plan.
|
||||
|
||||
a. This plan does not cover the following types of incidents:
|
||||
|
||||
i. Incidents that affect customers or partners but have no effect on the organization’s systems; in this case, the customer must employ their own continuity processes to make sure that they can continue to interact with the organization and its systems.
|
||||
|
||||
i. Incidents that affect cloud infrastructure suppliers at the core infrastructure level, including but not limited to Google, Heroku, and Amazon Web Services. The organization depends on such suppliers to employ their own continuity processes.
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Relocation*
|
||||
|
||||
i. If the organization’s primary work site is unavailable, an alternate work site shall be used by designated personnel. The organization’s alternate work site is located at [list the address of the alternate work site that the organization will use].
|
||||
|
||||
i. The personnel required to report to the alternate work site during a disaster includes [list the personnel titles responsible for reporting to the alternate work site].
|
||||
|
||||
a. *Critical Services, Key Tasks and, Service Level Agreements (SLAs)*
|
||||
|
||||
i. The following services and technologies are considered to be critical for business operations, and must immediately be restored (in priority order):
|
||||
|
||||
1. [list the critical services and technologies that must remain running during a disaster]
|
||||
|
||||
i. The following key tasks and SLAs must be considered during a disaster recovery event, in accordance with the organization’s objectives, agreements, and legal, contractual or regulatory obligations:
|
||||
|
||||
1. [list of key tasks / SLAs that must be kept operational, with respective deadlines]
|
||||
|
||||
a. The organization’s Recovery Time Objective (RTO) is [set the maximum amount of time before critical processes must be restored, to include relocation and getting critical services/technologies back online]. Relocation and restoration of critical services and technologies must be completed within this time period.
|
||||
|
||||
a. *Notification of Plan Initiation*
|
||||
|
||||
i. The following personnel must be notified when this plan is initiated:
|
||||
|
||||
1. [list all personnel (including titles) that must be notified of plan initiation ]
|
||||
|
||||
i. [person responsible for notifications, including title] is responsible for notifying the personnel listed above.
|
||||
|
||||
a. *Plan Deactivation*
|
||||
|
||||
i. This plan must only be deactivated by [person or persons with authority to deactivate the plan, including job title].
|
||||
|
||||
i. In order for this plan to be deactivated, all relocation activities and critical service / technology tasks as detailed above must be fully completed and/or restored. If the organization is still operating in an impaired scenario, the plan may still be kept active at the discretion of [person or persons with authority to deactivate the plan, including job title].
|
||||
|
||||
i. The following personnel must be notified when this plan is deactivated:
|
||||
|
||||
1. [list all personnel (including titles) that must be notified of plan activation]
|
||||
|
||||
a. The organization must endeavor to restore its normal level of business operations as soon as possible.
|
||||
|
||||
a. A list of relevant points of contact both internal and external to the organization is enclosed in Appendix A.
|
||||
|
||||
a. During a crisis, it is vital for certain recovery tasks to be performed right away. The following actions are pre-authorized in the event of a disaster recovery event:
|
||||
|
||||
i. [job title] must take all steps specified in this disaster recovery plan in order to recover the organization’s information technology infrastructure and services.
|
||||
|
||||
i. [job title] is authorized to make urgent purchases of equipment and services up to [amount].
|
||||
|
||||
i. [job title] is authorized to communicate with clients.
|
||||
|
||||
i. [job title] is authorized to communicate with the public.
|
||||
|
||||
i. [job title] is authorized to communicate with public authorities such as state and local governments and law enforcement.
|
||||
|
||||
i. [job title] is authorized to cooperate with [name of supplier/outsourcing partner].
|
||||
|
||||
i. [add/modify/remove authorizations in this section as necessary]
|
||||
|
||||
a. Specific recovery steps for information systems infrastructure and services are provided in Appendix B.
|
||||
|
||||
\pagebreak
|
||||
|
||||
# Appendix A: Relevant Points of Contact
|
||||
|
||||
Internal Contacts
|
||||
|
||||
+------------------+-------------------+------------------+------------------+-----------------+
|
||||
| Name | Job Title | Phone Number | Email Address |Alternate Contact|
|
||||
+==================+===================+==================+==================+=================+
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
+------------------+-------------------+------------------+------------------+-----------------+
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
+------------------+-------------------+------------------+------------------+-----------------+
|
||||
|
||||
External Contacts
|
||||
|
||||
+------------------+-------------------+------------------+------------------+-----------------+
|
||||
| Name | Job Title | Phone Number | Email Address |Alternate Contact|
|
||||
+==================+===================+==================+==================+=================+
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
+------------------+-------------------+------------------+------------------+-----------------+
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
+------------------+-------------------+------------------+------------------+-----------------+
|
||||
|
||||
\pagebreak
|
||||
|
||||
# Appendix B: Recovery Steps for Information Systems Infrastructure & Services
|
||||
|
||||
Specific recovery procedures are described in detail below:
|
||||
|
||||
+----------------------------+----------------------+------------------------------------+
|
||||
| Recovery Procedure | Person Responsible | Person(s) Notified When Complete |
|
||||
+============================+======================+====================================+
|
||||
| System to be recovered: | | |
|
||||
| | | |
|
||||
+----------------------------+----------------------+------------------------------------+
|
||||
| task 1: | | |
|
||||
| | | |
|
||||
+----------------------------+----------------------+------------------------------------+
|
||||
| task 2: | | |
|
||||
| | | |
|
||||
+----------------------------+----------------------+------------------------------------+
|
||||
| System to be recovered: | | |
|
||||
| | | |
|
||||
+----------------------------+----------------------+------------------------------------+
|
||||
| task 1: | | |
|
||||
| | | |
|
||||
+----------------------------+----------------------+------------------------------------+
|
||||
| task 2: | | |
|
||||
| | | |
|
||||
+----------------------------+----------------------+------------------------------------+
|
@ -7,7 +7,76 @@ majorRevisions:
|
||||
- date: Jun 1 2018
|
||||
comment: Initial document
|
||||
---
|
||||
# Purpose and Scope
|
||||
|
||||
a. This policy defines organizational requirements for the use of cryptographic controls, as well as the requirements for cryptographic keys, in order to protect the confidentiality, integrity, authenticity and nonrepudiation of information.
|
||||
|
||||
a. This policy applies to all systems, equipment, facilities and information within the scope of the organization’s information security program.
|
||||
|
||||
a. All employees, contractors, part-time and temporary workers, service providers, and those employed by others to perform work on behalf of the organization having to do with cryptographic systems, algorithms, or keying material are subject to this policy and must comply with it.
|
||||
|
||||
# Background
|
||||
|
||||
a. This policy defines the high level objectives and implementation instructions for the organization’s use of cryptographic algorithms and keys. It is vital that the organization adopt a standard approach to cryptographic controls across all work centers in order to ensure end-to-end security, while also promoting interoperability. This document defines the specific algorithms approved for use, requirements for key management and protection, and requirements for using cryptography in cloud environments.
|
||||
|
||||
# Policy
|
||||
|
||||
a. The organization must protect individual systems or information by means of cryptographic controls as defined in Table 3:
|
||||
|
||||
\pagebreak
|
||||
|
||||
+---------------------+-------------------+----------------+--------------+
|
||||
| **Name of System/** | **Cryptographic** | **Encryption** | **Key Size** |
|
||||
| **Type of** | **Tool** | **Algorithm** | |
|
||||
| **Information** | | | |
|
||||
+=====================+===================+================+==============+
|
||||
| Public Key | OpenSSL | AES-256 | 256-bit key |
|
||||
| Infrastructure for | | | |
|
||||
| Authentication | | | |
|
||||
+---------------------+-------------------+----------------+--------------+
|
||||
| | | | |
|
||||
+---------------------+-------------------+----------------+--------------+
|
||||
| Data Encryption | OpenSSL | AES-256 | 256-bit key |
|
||||
| Keys | | | |
|
||||
+---------------------+-------------------+----------------+--------------+
|
||||
| | | | |
|
||||
+---------------------+-------------------+----------------+--------------+
|
||||
| Virtual Private | OpenSSL and | AES-256 | 256-bit key |
|
||||
| Network (VPN) | OpenVPN | | |
|
||||
| keys | | | |
|
||||
+---------------------+-------------------+----------------+--------------+
|
||||
| | | | |
|
||||
+---------------------+-------------------+----------------+--------------+
|
||||
| Website SSL | OpenSSL, CERT | AES-256 | 256-bit key |
|
||||
| Certificate | | | |
|
||||
+---------------------+-------------------+----------------+--------------+
|
||||
|
||||
Table 3: Cryptographic Controls
|
||||
|
||||
|
||||
|
||||
b. Except where otherwise stated, keys must be managed by their owners.
|
||||
|
||||
c. Cryptographic keys must be protected against loss, change or destruction by applying appropriate access control mechanisms to prevent unauthorized use and backing up keys on a regular basis.
|
||||
|
||||
d. When required, customers of the organization’s cloud-based software or platform offering must be able to obtain information regarding:
|
||||
|
||||
i. The cryptographic tools used to protect their information.
|
||||
|
||||
i. Any capabilities that are available to allow cloud service customers to apply their own cryptographic solutions.
|
||||
|
||||
i. The identity of the countries where the cryptographic tools are used to store or transfer cloud service customers’ data.
|
||||
|
||||
a. The use of organizationally-approved encryption must be governed in accordance with the laws of the country, region, or other regulating entity in which users perform their work. Encryption must not be used to violate any laws or regulations including import/export restrictions. The encryption used by the Company conforms to international standards and U.S. import/export requirements, and thus can be used across international boundaries for business purposes.
|
||||
|
||||
a. All key management must be performed using software that automatically manages access control, secure storage, backup and rotation of keys. Specifically:
|
||||
|
||||
i. The key management service must provide key access to specifically-designated users, with the ability to encrypt/decrypt information and generate data encryption keys.
|
||||
|
||||
i. The key management service must provide key administration access to specifically-designated users, with the ability to create, schedule delete, enable/disable rotation, and set usage policies for keys.
|
||||
|
||||
i. The key management service must store and backup keys for the entirety of their operational lifetime.
|
||||
|
||||
i. The key management service must rotate keys at least once every 12 months.
|
||||
|
||||
# Overview
|
||||
|
||||
The XXX Policy governs X.
|
||||
|
@ -10,6 +10,102 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
a. This security incident response policy is intended to establish controls to ensure detection of security vulnerabilities and incidents, as well as quick reaction and response to security breaches.
|
||||
|
||||
a. This document also provides implementing instructions for security incident response, to include definitions, procedures, responsibilities, and performance measures (metrics and reporting mechanisms).
|
||||
|
||||
a. This policy applies to all users of information systems within the organization. This typically includes employees and contractors, as well as any external parties that come into contact with systems and information controlled by the organization (hereinafter referred to as “users”). This policy must be made readily available to all users.
|
||||
|
||||
# Background
|
||||
|
||||
a. A key objective of the organization’s Information Security Program is to focus on detecting information security weaknesses and vulnerabilities so that incidents and breaches can be prevented wherever possible. The organization is committed to protecting its employees, customers, and partners from illegal or damaging actions taken by others, either knowingly or unknowingly. Despite this, incidents and data breaches are likely to happen; when they do, the organization is committed to rapidly responding to them, which may include identifying, containing, investigating, resolving , and communicating information related to the breach.
|
||||
|
||||
a. This policy requires that all users report any perceived or actual information security vulnerability or incident as soon as possible using the contact mechanisms prescribed in this document. In addition, the organization must employ automated scanning and reporting mechanisms that can be used to identify possible information security vulnerabilities and incidents. If a vulnerability is identified, it must be resolved within a set period of time based on its severity. If an incident is identified, it must be investigated within a set period of time based on its severity. If an incident is confirmed as a breach, a set procedure must be followed to contain, investigate, resolve, and communicate information to employees, customers, partners and other stakeholders.
|
||||
|
||||
c. Within this document, the following definitions apply:
|
||||
|
||||
i. *Information Security Vulnerability:* a vulnerability in an information system, information system security procedures, or administrative controls that could be exploited to gain unauthorized access to information or to disrupt critical processing.
|
||||
|
||||
i. *Information Security Incident:* a suspected, attempted, successful, or imminent threat of unauthorized access, use, disclosure, breach, modification, or destruction of information; interference with information technology operations; or significant violation of information security policy.
|
||||
|
||||
# Policy
|
||||
a. All users must report any system vulnerability , incident, or event pointing to a possible incident to the Information Security Manager (ISM) as quickly as possible but no later than 24 hours. Incidents must be reported by sending an email message to <insert email address here> with details of the incident.
|
||||
|
||||
a. Users must be trained on the procedures for reporting information security incidents or discovered vulnerabilities, and their responsibilities to report such incidents. Failure to report information security incidents shall be considered to be a security violation and will be reported to the Human Resources (HR) Manager for disciplinary action.
|
||||
|
||||
a. Information and artifacts associated with security incidents (including but not limited to files, logs, and screen captures) must be preserved in the event that they need to be used as evidence of a crime.
|
||||
|
||||
a. All information security incidents must be responded to through the incident management procedures defined below.
|
||||
|
||||
a. In order to appropriately plan and prepare for incidents, the organization must review incident response procedures at least once per year for currency, and update as required.
|
||||
|
||||
a. The incident response procedure must be tested on at least twice per year
|
||||
|
||||
a. The incident response logs must be reviewed once per month to assess response effectiveness.
|
||||
|
||||
# Procedure For Establishing Incident Response System
|
||||
|
||||
a. Define on-call schedule and assign an Information Security Manager (ISM) responsible for managing incident response procedure during each availability window.
|
||||
|
||||
a. Define notification channel to alert the on-call ISM of a potential security incident. Establish company resource that includes up to date contact information for on-call ISM.
|
||||
|
||||
a. Assign management sponsors from the Engineering, Legal, HR, Marketing, and C-Suite teams.
|
||||
|
||||
a. Distribute Procedure For Execute Incident Response to all staff and ensure up-to-date versions are accessible in a dedicated company resource.
|
||||
|
||||
a. Require all staff to complete training for Procedure For Executing Incident Response at least twice per year.
|
||||
|
||||
# Procedure For Executing Incident Response
|
||||
|
||||
a. When an information security incident is identified or detected, users must notify their immediate manager within 24 hours. The manager must immediately notify the ISM on call for proper response. The following information must be included as part of the notification:
|
||||
|
||||
i. Description of the incident
|
||||
|
||||
i. Date, time, and location of the incident
|
||||
|
||||
i. Person who discovered the incident
|
||||
|
||||
i. How the incident was discovered
|
||||
|
||||
i. Known evidence of the incident
|
||||
|
||||
i. Affected system(s)
|
||||
|
||||
a. Within 48 hours of the incident being reported, the ISM shall conduct a preliminary investigation and risk assessment to review and confirm the details of the incident. If the incident is confirmed, the ISM must assess the impact to the organization and assign a severity level, which will determine the level of remediation effort required:
|
||||
|
||||
i. High: the incident is potentially catastrophic to the organization and/or disrupts the organization’s day-to-day operations; a violation of legal, regulatory or contractual requirements is likely.
|
||||
|
||||
i. Medium: the incident will cause harm to one or more business units within the organization and/or will cause delays to a business unit’s activities.
|
||||
|
||||
i. Low: the incident is a clear violation of organizational security policy, but will not substantively impact the business.
|
||||
|
||||
|
||||
a. The ISM, in consultation with management sponsors, shall determine appropriate incident response activities in order to contain and resolve incidents.
|
||||
|
||||
a. The ISM must take all necessary steps to preserve forensic evidence (e.g. log information, files, images) for further investigation to determine if any malicious activity has taken place. All such information must be preserved and provided to law enforcement if the incident is determined to be malicious.
|
||||
|
||||
a. If the incident is deemed as High or Medium, the ISM must work with the VP Brand/Creative, General Counsel, and HR Manager to create and execute a communications plan that communicates the incident to users, the public, and others affected.
|
||||
|
||||
a. The ISM must take all necessary steps to resolve the incident and recover information systems, data, and connectivity. All technical steps taken during an incident must be documented in the organization’s incident log, and must contain the following:
|
||||
|
||||
i. Description of the incident
|
||||
|
||||
i. Incident severity level
|
||||
|
||||
i. Root cause (e.g. source address, website malware, vulnerability)
|
||||
|
||||
i. Evidence
|
||||
|
||||
i. Mitigations applied (e.g. patch, re-image)
|
||||
|
||||
i. Status (open, closed, archived)
|
||||
|
||||
i. Disclosures (parties to which the details of this incident were disclosed to, such as customers, vendors, law enforcement, etc.)
|
||||
|
||||
a. After an incident has been resolved, the ISM must conduct a post mortem that includes root cause analysis and documentation any lessons learned.
|
||||
|
||||
a. Depending on the severity of the incident, the Chief Executive Officer (CEO) may elect to contact external authorities, including but not limited to law enforcement, private investigation firms, and government organizations as part of the response to the incident.
|
||||
|
||||
a. The ISM must notify all users of the incident, conduct additional training if necessary, and present any lessons learned to prevent future occurrences. Where necessary, the HR Manager must take disciplinary action if a user’s activity is deemed as malicious.
|
||||
|
@ -8,22 +8,86 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The Information Security Policy is a composite policy referencing other Acme policies relevant to information security.
|
||||
a. This information security policy defines the purpose, principles, objectives and basic rules for information security management.
|
||||
|
||||
# Component Policies
|
||||
a. This document also defines procedures to implement high level information security protections within the organization, including definitions, procedures, responsibilities and performance measures (metrics and reporting mechanisms).
|
||||
|
||||
The Acme Information Security Policy is composed of:
|
||||
a. This policy applies to all users of information systems within the organization. This typically includes employees and contractors, as well as any external parties that come into contact with systems and information controlled by the organization (hereinafter referred to as “users”). This policy must be made readily available to all users.
|
||||
|
||||
- [Application Security Policy (*Acme-ASP.pdf*)](Acme-ASP.pdf) {-}
|
||||
- [Cyber Risk Management Policy (*Acme-CRP.pdf*)](Acme-CRP.pdf) {-}
|
||||
- [Data Classification Policy (*Acme-DCP.pdf*)](Acme-DCP.pdf) {-}
|
||||
- [Data Retention Policy (*Acme-ASP.pdf*)](Acme-DRP.pdf) {-}
|
||||
- [Datacenter Security Policy (*Acme-ASP.pdf*)](Acme-DSP.pdf) {-}
|
||||
- [Encryption Policy (*Acme-ASP.pdf*)](Acme-EP.pdf) {-}
|
||||
- [Password Policy (*Acme-ASP.pdf*)](Acme-PWP.pdf) {-}
|
||||
- [Remote Access Policy (*Acme-ASP.pdf*)](Acme-REAP.pdf) {-}
|
||||
- [Removable Media Policy (*Acme-ASP.pdf*)](Acme-RMP.pdf) {-}
|
||||
- [Security Incident Response Policy (*Acme-ASP.pdf*)](Acme-SIRP.pdf) {-}
|
||||
- [Workstation Security Policy (*Acme-ASP.pdf*)](Acme-WSP.pdf) {-}
|
||||
# Background
|
||||
|
||||
a. This policy defines the high level objectives and implementation instructions for the organization’s information security program. It includes the organization’s information security objectives and requirements; such objectives and requirements are to be referenced when setting detailed information security policy for other areas of the organization. This policy also defines management roles and responsibilities for the organization’s Information Security Management System (ISMS). Finally, this policy references all security controls implemented within the organization.
|
||||
|
||||
a. Within this document, the following definitions apply:
|
||||
|
||||
i. *Confidentiality*: a characteristic of information or information systems in which such information or systems are only available to authorized entities.
|
||||
|
||||
i. *Integrity*: a characteristic of information or information systems in which such information or systems may only be changed by authorized entities, and in an approved manner.
|
||||
|
||||
i. *Availability*: a characteristic of information or information systems in which such information or systems can be accessed by authorized entities whenever needed.
|
||||
|
||||
i. *Information Security*: the act of preserving the confidentiality, integrity, and, availability of information and information systems.
|
||||
|
||||
i. *Information Security Management System (ISMS)*: the overall management process that includes the planning, implementation, maintenance, review, and, improvement of information security.
|
||||
|
||||
# References
|
||||
|
||||
a. Encryption Policy
|
||||
|
||||
a. Data Center Security Policy
|
||||
|
||||
a. Disaster Recovery Policy
|
||||
|
||||
a. Password Policy
|
||||
|
||||
a. Remote Access Policy
|
||||
|
||||
a. Removable Media/Cloud Storage/BYOD Policy
|
||||
|
||||
a. Risk Assessment Policy
|
||||
|
||||
a. Security Incident Response Policy
|
||||
|
||||
a. Software Development Lifecycle Policy
|
||||
|
||||
a. System Availability Policy
|
||||
|
||||
a. Workstation Security Policy
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Managing Information Security*
|
||||
|
||||
i. The organization’s main objectives for information security include the following:
|
||||
|
||||
1. [list the reasons/objectives for maintaining information security at the organization. Examples include a better market image, reduced risk of data breaches and compromises, and compliance with legal, regulatory, and contractual requirements.]
|
||||
|
||||
i. The organization’s objectives for information security are in line with the organization’s business objectives, strategy, and plans.
|
||||
|
||||
i. Objectives for individual security controls or groups of controls are proposed by the company management team, including but not limited to [list key roles inside the organization that will participate in information security matters], and others as appointed by the CEO; these security controls are approved by the CEO in accordance with the Risk Assessment Policy (Reference (a)).
|
||||
|
||||
i. All objectives must be reviewed at least once per year.
|
||||
|
||||
i. The company will measure the fulfillment of all objectives. The measurement will be performed at least once per year. The results must be analyzed, evaluated, and reported to the management team.
|
||||
|
||||
a. *Information Security Requirements*
|
||||
|
||||
i. This policy and the entire information security program must be compliant with legal and regulatory requirements as well as with contractual obligations relevant to the organization.
|
||||
|
||||
i. All employees, contractors, and other individuals subject to the organization’s information security policy must read and acknowledge all information security policies.
|
||||
|
||||
i. The process of selecting information security controls and safeguards for the organization is defined in Reference (a).
|
||||
|
||||
i. The organization prescribes guidelines for remote workers as part of the Remote Access Policy (reference (b)).
|
||||
|
||||
i. To counter the risk of unauthorized access, the organization maintains a Data Center Security Policy (reference (c)).
|
||||
|
||||
i. Security requirements for the software development life cycle, including system development, acquisition and maintenance are defined in the Software Development Lifecycle Policy (reference (d)).
|
||||
|
||||
i. Security requirements for handling information security incidents are defined in the Security Incident Response Policy (reference (e)).
|
||||
|
||||
i. Disaster recovery and business continuity management policy is defined in the Disaster Recovery Policy (reference (f)).
|
||||
|
||||
i. Requirements for information system availability and redundancy are defined in the System Availability Policy (reference (g)).
|
||||
|
@ -8,6 +8,60 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
a. This log management and review policy defines specific requirements for information systems to generate, store, process, and aggregate appropriate audit logs across the organization’s entire environment in order to provide key information and detect indicators of potential compromise.
|
||||
|
||||
a. This policy applies to all information systems within the organization’s production network.
|
||||
|
||||
a. This policy applies to all employees, contractors, and partners of the organization that administer or provide maintenance on the organization’s production systems. Throughout this policy, these individuals are referred to as system administrators.
|
||||
|
||||
# Background
|
||||
|
||||
a. In order to measure an information system’s level of security through confidentiality, integrity, and availability, the system must collect audit data that provides key insights into system performance and activities. This audit data is collected in the form of system logs. Logging from critical systems, applications, and services provides information that can serve as a starting point for metrics and incident investigations. This policy provides specific requirements and instructions for how to manage such logs.
|
||||
|
||||
# Policy
|
||||
|
||||
a. All production systems within the organization shall record and retain audit-logging information that includes the following information:
|
||||
|
||||
i. Activities performed on the system.
|
||||
|
||||
i. The user or entity (i.e. system account) that performed the activity, including the system that the activity was performed from.
|
||||
|
||||
i. The file, application, or other object that the activity was performed on.
|
||||
|
||||
i. The time that the activity occurred.
|
||||
|
||||
i. The tool that the activity was performed with.
|
||||
|
||||
i. The outcome (e.g., success or failure) of the activity.
|
||||
|
||||
a. Specific activities to be logged must include, at a minimum:
|
||||
|
||||
i. Information (including authentication information such as usernames or passwords) is created, read, updated, or deleted.
|
||||
|
||||
i. Accepted or initiated network connections.
|
||||
|
||||
i. User authentication and authorization to systems and networks.
|
||||
|
||||
i. Granting, modification, or revocation of access rights, including adding a new user or group; changing user privileges, file permissions, database object permissions, firewall rules, and passwords.
|
||||
|
||||
i. System, network, or services configuration changes, including software installation, patches, updates, or other installed software changes.
|
||||
|
||||
i. Startup, shutdown, or restart of an application.
|
||||
|
||||
i. Application process abort, failure, or abnormal end, especially due to resource exhaustion or reaching a resource limit or threshold (such as CPU, memory, network connections, network bandwidth, disk space, or other resources), the failure of network services such as DHCP or DNS, or hardware fault.
|
||||
|
||||
i. Detection of suspicious and/or malicious activity from a security system such as an Intrusion Detection or Prevention System (IDS/IPS), anti-virus system, or anti-spyware system.
|
||||
|
||||
a. Unless technically impractical or infeasible, all logs must be aggregated in a central system so that activities across different systems can be correlated, analyzed, and tracked for similarities, trends, and cascading effects. Log aggregation systems must have automatic and timely log ingest, event and anomaly tagging and alerting, and ability for manual review.
|
||||
|
||||
a. Logs must be manually reviewed on a regular basis:
|
||||
|
||||
i. The activities of users, administrators and system operators must be reviewed on at least a monthly basis.
|
||||
|
||||
ii. Logs related to PII must be reviewed on at least a monthly basis in order to identify unusual behavior.
|
||||
|
||||
a. When using an outsourced cloud environment, logs must be kept on cloud environment access and use, resource allocation and utilization, and changes to PII. Logs must be kept for all administrators and operators performing activities in cloud environments.
|
||||
|
||||
a. All information systems within the organization must synchronize their clocks by implementing Network Time Protocol (NTP) or a similar capability. All information systems must synchronize with the same primary time source.
|
||||
|
@ -8,6 +8,133 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
a. This removable media, cloud storage and Bring Your Own Device (BYOD) policy defines the objectives, requirements and implementing instructions for storing data on removable media, in cloud environments, and on personally-owned devices, regardless of data classification level.
|
||||
|
||||
a. This policy applies to all information and data within the organization’s information security program, as well as all removable media, cloud systems and personally-owned devices either owned or controlled by the organization.
|
||||
|
||||
a. This policy applies to all users of information systems within the organization. This typically includes employees and contractors, as well as any external parties that come into contact with systems and information controlled by the organization (hereinafter referred to as “users”). This policy must be made readily available to all users.
|
||||
|
||||
# Background
|
||||
|
||||
a. This policy defines the procedures for safely using removable media, cloud storage and personally-owned devices to limit data loss or exposure. Such forms of storage must be strictly controlled because of the sensitive data that can be stored on them. Because each of these storage types are inherently ephemeral or portable in nature, it is possible for the organization to lose the ability to oversee or control the information stored on them if strict security standards are not followed.
|
||||
|
||||
a. This document consists of three sections pertaining to removable media, cloud storage, and personally-owned devices. Each section contains requirements and implementing instructions for the registration, management, maintenance, and disposition of each type of storage.
|
||||
|
||||
a. Within this policy, the term sensitive information refers to information that is classified as RESTRICTED or CONFIDENTIAL in accordance with the Data Classification Policy (reference (a)).
|
||||
|
||||
# References
|
||||
|
||||
a. Data Classification Policy
|
||||
|
||||
a. Asset Inventory
|
||||
|
||||
a. Security Incident Response Policy
|
||||
|
||||
a. Encryption Policy
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Removable Media*
|
||||
|
||||
i. All removable media in active use and containing data pertinent to the organization must be registered in the organization’s Asset Inventory (reference (b)).
|
||||
|
||||
i. All removable media listed in reference (b) must be re-inventoried on a quarterly basis to ensure that it is still within the control of the organization.
|
||||
|
||||
1. To re-inventory an item, the owner of the removable media must check in the item with the organization’s Information Security Manager (ISM).
|
||||
|
||||
1. The ISM must treat any removable media that cannot be located as lost, and a security incident report must be logged in accordance with the Security Incident Response Policy (reference (c)).
|
||||
|
||||
i. The owner of the removable media must conduct all appropriate maintenance on the item at intervals appropriate to the type of media, such as cleaning, formatting, labeling, etc.
|
||||
|
||||
i. The owner of the removable media, where practical, must ensure that an alternate or backup copy of the information located on the device exists.
|
||||
|
||||
i. Removable media must be stored in a safe place that has a reduced risk of fire or flooding damage.
|
||||
|
||||
i. If the storage item contains sensitive information, removable media must:
|
||||
|
||||
1. Be stored in a locked cabinet or drawer.
|
||||
|
||||
1. Store only encrypted data that is securely enciphered in accordance with the Encryption Policy (reference (d)).
|
||||
|
||||
i. All data on removable media devices must be erased, or the device must be destroyed, before it is reused or disposed of.
|
||||
|
||||
i. When removable media devices are disposed, the device owner must inform the ISM so that it can be removed from reference (b).
|
||||
|
||||
a. *Cloud Storage*
|
||||
|
||||
i. All cloud storage systems in active use and containing data pertinent to the organization must be registered in reference (b). Registration may be accomplished by manual or automated means.
|
||||
|
||||
|
||||
i. All cloud storage systems listed in reference (b) must be re-inventoried on a quarterly basis to ensure that it is still within the control of the organization. To re-inventory an item, the owner of the removable media must check in the item with the organization’s Information Security Manager (ISM). Re-inventory may be accomplished by manual or automated means.
|
||||
|
||||
i. The owner of the cloud storage system must conduct all appropriate maintenance on the system at regular intervals to include system configuration, access control, performance monitoring, etc.
|
||||
|
||||
i. Data on cloud storage systems must be replicated to at least one other physical location. Depending on the cloud storage provider, this replication may be automatically configured.
|
||||
|
||||
i. The organization must only use cloud storage providers that can demonstrate, either through security accreditation, demonstration, tour, or other means that their facilities are secured, both physically and electronically, using best practices.
|
||||
|
||||
i. If the cloud storage system contains sensitive information, that information must be encrypted in accordance with reference (d).
|
||||
|
||||
i. Data must be erased from from cloud storage systems using a technology and process that is approved by the ISM.
|
||||
|
||||
i. When use of a cloud storage system is discontinued, the system owner must inform the ISM so that it can be removed from reference (b).
|
||||
|
||||
a. *Personally-owned Devices*
|
||||
|
||||
i. Organizational data that is stored, transferred or processed on personally-owned devices remains under the organization’s ownership, and the organization retains the right to control such data even though it is not the owner of the device.
|
||||
|
||||
i. The ISM is responsible for conducting overall management of personally-owned devices, to include:
|
||||
|
||||
1. Installation and maintenance of Mobile Device Management (MDM) software that can effectively manage, control and wipe data under the organization’s control from personally-owned devices.
|
||||
|
||||
1. Maintain a list of job titles and/or persons authorized to use personally-owned devices for the organization’s business, as well as the applications and databases that may be accessed from such devices.
|
||||
|
||||
1. Maintain a list of applications prohibited from use on personally-owned devices, and ensuring that device users are aware of these restrictions.
|
||||
|
||||
i. Personally-identifiable information (PII) may not be stored, processed or accessed at any time on a personally-owned device.
|
||||
|
||||
i. The following acceptable use requirements must be observed by users of personally-owned devices:
|
||||
|
||||
1. All organizational data must be backed up at regular intervals.
|
||||
|
||||
1. MDM and endpoint protection software must be installed on the device at all times.
|
||||
|
||||
1. Sensitive information stored on the device must be encrypted in accordance with reference (d).
|
||||
|
||||
1. The device must be secured using a password, pin, unlock pattern, fingerprint or equivalent security mechanism.
|
||||
|
||||
1. The device must only connect to secure and encrypted wireless networks.
|
||||
|
||||
1. When using the device outside of the organization’s premises, it must not be left unattended, and if possible, physically secured.
|
||||
|
||||
1. When using the device in public areas, the owner must take measures to ensure that the data cannot be read or accessed by unauthorized persons.
|
||||
|
||||
1. Patches and updates must be installed regularly.
|
||||
|
||||
1. Classified information must be protected in accordance with reference (a).
|
||||
|
||||
1. The device owner must install the ISM before the device is disposed of, sold, or provided to a third party for servicing.
|
||||
|
||||
1. It is prohibited to:
|
||||
|
||||
a. Allow device access for anyone except its owner.
|
||||
|
||||
a. Store illegal materials on the device.
|
||||
|
||||
a. Install unlicensed software.
|
||||
|
||||
a. Locally-store passwords.
|
||||
|
||||
a. Transfer organizational data to other devices which have not been approved by the organization.
|
||||
|
||||
i. The organization must reserve the right to view, edit, and/or delete any organizational information that is stored, processed or transferred on the device.
|
||||
|
||||
i. The organization must reserve the right to perform full deletion of all of its data on the device if it considers that necessary for the protection of company-related data, without the consent of the device owner.
|
||||
|
||||
i. The organization will not pay the employees (the owners of BYOD) any fee for using the device for work purposes.
|
||||
|
||||
i. The organization will pay for any new software that needs to be installed for company use.
|
||||
|
||||
i. All security breaches related to personally-owned devices must be reported immediately to the ISM.
|
||||
|
@ -8,6 +8,92 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
a. This policy establishes the rules governing controls, monitoring, and removal of physical access to company’s facilities.
|
||||
|
||||
a. This policy applies to all staff, contractors, or third parties who require access to any physical location owned, operated, or otherwise occupied by the company. A separate policy exists for governing access to the company data center.
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Management responsibilities*
|
||||
|
||||
i. Management shall ensure:
|
||||
|
||||
1. appropriate entry controls are in place for secure areas
|
||||
|
||||
1. security personnel, identification badges, or electronic key cards should be used to validate employee access to facilities
|
||||
|
||||
1. confirm visitor & guest access procedure has been followed by host staff
|
||||
|
||||
1. management periodically reviews list of individuals with physical access to facilities
|
||||
|
||||
1. card access records and visitor logs are kept for a minimum of 90 days and are periodically reviewed for unusual activity
|
||||
|
||||
a. *Key access & card systems*
|
||||
|
||||
i. The following policies are applied to all facility access cards/keys:
|
||||
|
||||
1. Access cards/keys shall not be shared or loaned to others
|
||||
|
||||
1. Access cards/keys shall not have identifying information other than a return mail address
|
||||
|
||||
1. Access cards/keys shall be returned to Human Resources when they are no longer needed
|
||||
|
||||
1. Lost or stolen access cards/keys shall be reported immediately
|
||||
|
||||
1. If an employee changes to a role that no longer requires physical access or leaves the company, their access cards/keys will be suspended
|
||||
|
||||
1. Human Resources will regularly review physical security privileges and review access logs
|
||||
|
||||
\pagebreak
|
||||
|
||||
a. *Staff & contractor access procedure*
|
||||
|
||||
i. Access to physical locations is granted to employees and contractors based on individual job function and will be granted by Human Resources.
|
||||
|
||||
i. Any individual granted access to physical spaces will be issued a physical key or access key card. Key and card issuance is tracked by Human Resources and will be periodically reviewed.
|
||||
|
||||
i. In the case of termination, Human Resources should ensure immediate revocation of access
|
||||
(i.e. collection of keys, access cards, and any other asset used to enter facilities) through the offboarding procedure.
|
||||
|
||||
a. *Visitor & guest access procedure*
|
||||
|
||||
i. The following policies are applied to identification & authorization of visitors and guests:
|
||||
|
||||
1. All visitors must request and receive written onsite authorization from a staff member.
|
||||
|
||||
1. Visitor access shall be tracked with a sign in/out log. The log shall contain:visitor’s name, firm represented, purpose of visit, and onsite personnel authorizing access
|
||||
|
||||
1. The log shall be retained for a minimum of 90 days
|
||||
|
||||
1. Visitors shall be given a badge or other identification that visibly distinguishes visitors from onsite personnel
|
||||
|
||||
1. Visitor badges shall be surrendered before leaving the facility
|
||||
|
||||
a. *Audit controls & management*
|
||||
|
||||
i. Documented procedures and evidence of practice should be in place for this policy. Acceptable controls and procedures include:
|
||||
|
||||
1. visitor logs
|
||||
|
||||
1. access control procedures
|
||||
|
||||
1. operational key-card access systems
|
||||
|
||||
1. video surveillance systems (with retrievable data)
|
||||
|
||||
1. ledgers if issuing physical keys
|
||||
|
||||
a. *Enforcement*
|
||||
|
||||
i. Employees, contractors, or third parties found in violation of this policy (whether intentional or accidental) may be subject to disciplinary action, including:
|
||||
|
||||
1. reprimand
|
||||
|
||||
1. loss of access to premises
|
||||
|
||||
1. termination
|
||||
|
||||
|
||||
|
||||
The XXX Policy governs X.
|
||||
|
@ -8,6 +8,32 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
a. The Password Policy describes the procedure to select and securely manage passwords.
|
||||
|
||||
a. This policy applies to all employees, contractors, and any other personnel who have an account on any system that resides at any company facility or has access to the company network.
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Rotation requirements*
|
||||
|
||||
i. All system-level passwords should be rotated on at least a quarterly basis. All user-level passwords should be rotated at least every six months.
|
||||
|
||||
i. If a credential is suspected of being compromised, the password in question should be rotated immediately and the Engineering/Security team should be notified.
|
||||
|
||||
a. Password protection
|
||||
|
||||
i. All passwords are treated as confidential information and should not be shared with anyone. If you receive a request to share a password, deny the request and contact the system owner for assistance in provisioning an individual user account.
|
||||
|
||||
i. Do not write down passwords, store them in emails, electronic notes, or mobile devices, or share them over the phone. If you must store passwords electronically, do so with a password manager that has been approved by IT. If you truly must share a password, do so through a designated password manager or grant access to an application through a single sign on provider.
|
||||
|
||||
i. Do not use the “Remember Password” feature of applications and web browsers.
|
||||
|
||||
i. If you suspect a password has been compromised, rotate the password immediately and notify engineering/security.
|
||||
|
||||
a. Enforcement
|
||||
|
||||
i. An employee or contractor found to have violated this policy may be subject to disciplinary action.
|
||||
|
||||
|
||||
The XXX Policy governs X.
|
||||
|
@ -7,15 +7,24 @@ majorRevisions:
|
||||
- date: Jun 1 2018
|
||||
comment: Initial document
|
||||
---
|
||||
# Purpose and Scope
|
||||
|
||||
# Overview
|
||||
a. This policy addresses policy education requirements for employees and contractors.
|
||||
|
||||
The Policy Training Policy addresses policy education requirements for Acme employees and contractors.
|
||||
|
||||
# Adherence
|
||||
|
||||
Assignees are reminded that adherence to assigned policies is binding under the terms of their Acme Employment Offer Letter and/or their Acme Independent Contractor Agreement.
|
||||
a. This policy applies to all full-time employees, part-time employees, and contractors. Adherence to assigned policies is binding under their Employment Offer Letter and/or Independent Contractor Agreement.
|
||||
|
||||
# Applicability
|
||||
|
||||
Upon each full-time, part-time or contractor addition, the hiring manager determines which subset of of Acme Policies apply to that individual. The individual is tasked with reading the assigned policies within 5 working days. The initial assignment date, scope, and completion date are entered into the [Ledger].
|
||||
a. Upon hire of a new employee or contractor, the Hiring Manager will determine which subsets of policies will apply to that individual. The individual will have five working days to read the assigned policies. The following will be logged in the Policy Training Policy Ledger:
|
||||
|
||||
i. Assignment date
|
||||
|
||||
i. Completion date
|
||||
|
||||
i. Policy
|
||||
|
||||
i. Assignee
|
||||
|
||||
i. Assigner
|
||||
|
||||
i. Notes
|
||||
|
@ -25,6 +25,4 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
The XXX Policy governs X.
|
||||
# Coming Soon
|
@ -1,5 +1,5 @@
|
||||
name: Processing Integrity Management Policy
|
||||
acronym: PIMP
|
||||
name: Processing Integrity Policy
|
||||
acronym: PIP
|
||||
satisfies:
|
||||
TSC:
|
||||
- PI1.1
|
||||
@ -12,6 +12,4 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
The XXX Policy governs X.
|
||||
# Coming Soon
|
@ -10,6 +10,50 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
a. The purpose of this policy is to define requirements for connecting to the organization’s systems and networks from remote hosts, including personally-owned devices, in order to minimize data loss/exposure.
|
||||
|
||||
a. This policy applies to all users of information systems within the organization. This typically includes employees and contractors, as well as any external parties that come into contact with systems and information controlled by the organization (hereinafter referred to as “users”). This policy must be made readily accessible to all users.
|
||||
|
||||
# Background
|
||||
|
||||
a. The intent of this policy is to minimize the organization’s exposure to damages which may result from the unauthorized remote use of resources, including but not limited to: the loss of sensitive, company confidential data and intellectual property; damage to the organization’s public image; damage to the organization’s internal systems; and fines and/or other financial liabilities incurred as a result of such losses.
|
||||
|
||||
a. Within this policy, the following definitions apply:
|
||||
|
||||
i. *Mobile computing equipment:* includes portable computers, mobile phones, smart phones, memory cards and other mobile equipment used for storage, processing and transfer of data.
|
||||
|
||||
i. *Remote host:* is defined as an information system, node or network that is not under direct control of the organization.
|
||||
|
||||
i. *Telework:* the act of using mobile computing equipment and remote hosts to perform work outside the organization’s physical premises. Teleworking does not include the use of mobile phones.
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Security Requirements for Remote Hosts and Mobile Computing Equipment*
|
||||
|
||||
i. Caution must be exercised when mobile computing equipment is placed or used in uncontrolled spaces such as vehicles, public spaces, hotel rooms, meeting places, conference centers, and other unprotected areas outside the organization’s premises.
|
||||
|
||||
i. When using remote hosts and mobile computing equipment, users must take care that information on the device (e.g. displayed on the screen) cannot be read by unauthorized persons if the device is being used to connect to the organization’s systems or work with the organization’s data.
|
||||
|
||||
i. Remote hosts must be updated and patched for the latest security updates on at least a monthly basis.
|
||||
|
||||
i. Remote hosts must have endpoint protection software (e.g. malware scanner) installed and updated at all times.
|
||||
|
||||
i. Persons using mobile computing equipment off-premises are responsible for regular backups of organizational data that resides on the the device.
|
||||
|
||||
i. Access to the organization’s systems must be done through an encrypted and authenticated VPN connection with multi-factor authentication enabled. All users requiring remote access must be provisioned with VPN credentials from the organization’s information technology team. VPN keys must be rotated at least twice per year. Revocation of VPN keys must be included in the Offboarding Policy.
|
||||
|
||||
i. Information stored on mobile computing equipment must be encrypted using hard drive full disk encryption.
|
||||
|
||||
a. *Security Requirements for Telework*
|
||||
|
||||
i. Employees must be specifically authorized for telework in writing from their hiring manager .
|
||||
|
||||
i. Only device’s assigned owner is permitted to use remote nodes and mobile computing equipment. Unauthorized users (such as others living or working at the location where telework is performed) are not permitted to use such devices.
|
||||
|
||||
i. Devices must be authorized using certificates
|
||||
|
||||
i. Users performing telework are responsible for the appropriate configuration of the local network used for connecting to the Internet at their telework location.
|
||||
|
||||
i. Users performing telework must protect the organization’s intellectual property rights, either for software or other materials that are present on remote nodes and mobile computing equipment.
|
||||
|
@ -10,6 +10,79 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
#Appendices
|
||||
Appendix A: Retention Periods
|
||||
|
||||
The XXX Policy governs X.
|
||||
# Purpose and Scope
|
||||
|
||||
a. This data retention policy defines the objectives and requirements for data retention within the organization.
|
||||
|
||||
a. This policy covers all data within the organization’s custody or control, irregardless of the medium the data is stored in (electronic form, paper form, etc.) Within this policy, the medium which holds data is referred to as information, no matter what form it is in.
|
||||
|
||||
a. This policy applies to all users of information systems within the organization. This typically includes employees and contractors, as well as any external parties that come into contact with systems and information the organization owns or controls (hereinafter referred to as “users”). This policy must be made readily available to all users.
|
||||
|
||||
# Background
|
||||
|
||||
a. The organization is bound by multiple legal, regulatory and contractual obligations with regard to the data it retains. These obligations stipulate how long data can be retained, and how data must be destroyed. Examples of legal, regulatory and contractual obligations include laws and regulations in the local jurisdiction where the organization conducts business, and contracts made with employees, customers, service providers, partners and others.
|
||||
|
||||
a. The organization may also be involved in events such as litigation or disaster recovery scenarios that require it to have access to original information in order to protect the organization’s interests or those of its employees, customers, service providers, partners and others. As a result, the organization may need to archive and store information for longer that it may be needed for day-to-day operations.
|
||||
|
||||
\pagebreak
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Information Retention*
|
||||
|
||||
i. Retention is defined as the maintenance of information in a production or live environment which can be accessed by an authorized user in the ordinary course of business.
|
||||
|
||||
i. Information used in the development, staging, and testing of systems shall not be retained beyond their active use period nor copied into production or live environments.
|
||||
|
||||
i. By default, the retention period of information shall be an active use period of exactly two years from its creation unless an exception is obtained permitting a longer or shorter retention period. The business unit responsible for the information must request the exception.
|
||||
|
||||
i. After the active use period of information is over in accordance with this policy and approved exceptions, information must be archived for a defined period. Once the defined archive period is over, the information must be destroyed.
|
||||
|
||||
i. Each business unit is responsible for the information it creates, uses, stores, processes and destroys, according to the requirements of this policy. The responsible business unit is considered to be the information owner.
|
||||
|
||||
i. The organization’s legal counsel may issue a litigation hold to request that information relating to potential or actual litigation, arbitration or other claims, demands, disputes or regulatory action be retained in accordance with instructions from the legal counsel.
|
||||
|
||||
i. Each employee and contractor affiliated with the company must return information in their possession or control to the organization upon separation and/or retirement.
|
||||
|
||||
i. Information owners must enforce the retention, archiving and destruction of information, and communicate these periods to relevant parties.
|
||||
|
||||
a. *Information Archiving*
|
||||
|
||||
i. Archiving is defined as secured storage of information such that the information is rendered inaccessible by authorized users in the ordinary course of business but can be retrieved by an administrator designated by company management.
|
||||
|
||||
1. Physical (e.g., paper) records must be archived in secured storage (onsite or offsite) and clearly labeled in archive boxes naming the information owner.
|
||||
|
||||
1. Electronic records must be archived with strict access controls set by the information owner and appropriate to secure the confidentiality, integrity and accessibility of the information.
|
||||
|
||||
i. The default archiving period of information shall be 7 years unless an approved exception permits a longer or shorter period. Exceptions must be requested by the information owner.
|
||||
|
||||
1. As a guideline, an archiving period of more than 7 years may be granted for information with a vital historical purpose such as corporate records, contracts, and technical/trade secrets.
|
||||
|
||||
1. As a guideline, an archiving period of less than 7 years may be granted for information with a limited business purpose such as email, travel itineraries, pre-trip advisories, or to comply with specific legal, contractual and/or regulatory requirements (e.g., PCI DSS, GDPR, etc.)
|
||||
|
||||
i. Information must be destroyed (defined below) at the end of the elapsed archiving period.
|
||||
|
||||
a. *Information Destruction*
|
||||
|
||||
i. Destruction is defined as the physical or technical destruction sufficient to render the information contained in the document irretrievable by ordinary commercially-available means.
|
||||
|
||||
i. The organization must maintain and enforce a detailed list of approved destruction methods appropriate for each type of information archived, whether in physical storage media such as CD-ROMs, DVDs, backup tapes, hard drives, mobile devices, portable drives or in database records or backup files. Physical information in paper form must be shredded using an authorized shredding device; waste must be periodically removed by approved personnel.
|
||||
|
||||
a. Retention and archival periods for information that is created, processed, stored and used by the organization is defined in Appendix A, “Retention Periods.”
|
||||
|
||||
\pagebreak
|
||||
|
||||
# Appendix A: Retention Periods
|
||||
|
||||
+------------------+-------------------+------------------+------------------+-----------------+
|
||||
| Information Type | Information Owner | Storage Location | Retention Period | Archival Period |
|
||||
+==================+===================+==================+==================+=================+
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
+------------------+-------------------+------------------+------------------+-----------------+
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
+------------------+-------------------+------------------+------------------+-----------------+
|
@ -8,6 +8,130 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
a. The purpose of this policy is to define the methodology for the assessment and treatment of information security risks within the organization, and to define the acceptable level of risk as set by the organization’s leadership.
|
||||
|
||||
a. Risk assessment and risk treatment are applied to the entire scope of the organization’s information security program, and to all assets which are used within the organization or which could have an impact on information security within it.
|
||||
|
||||
a. This policy applies to all employees of the organization who take part in risk assessment and risk treatment.
|
||||
|
||||
# Background
|
||||
|
||||
a. A key element of the organization’s information security program is a holistic and systematic approach to risk management. This policy defines the requirements and processes for the organization to identify information security risks. The process consists of four parts: identification of the organization’s assets, as well as the threats and vulnerabilities that apply; assessment of the likelihood and consequence (risk) of the threats and vulnerabilities being realized, identification of treatment for each unacceptable risk, and evaluation of the residual risk after treatment.
|
||||
|
||||
# References
|
||||
|
||||
a. Risk Assessment Report Template
|
||||
|
||||
# Policy
|
||||
|
||||
a. *Risk Assessment*
|
||||
|
||||
i. The risk assessment process includes the identification of threats and vulnerabilities having to do with company assets.
|
||||
|
||||
i. The first step in the risk assessment is to identify all assets within the scope of the information security program; in other words, all assets which may affect the confidentiality, integrity, and/or availability of information in the organization. Assets may include documents in paper or electronic form, applications, databases, information technology equipment, infrastructure, and external/outsourced services and processes. For each asset, an owner must be identified.
|
||||
|
||||
i. The next step is to identify all threats and vulnerabilities associated with each asset. Threats and vulnerabilities must be listed in a risk assessment table. Each asset may be associated with multiple threats, and each threat may be associated with multiple vulnerabilities. A sample risk assessment table is provided as part of the Risk Assessment Report Template (reference (a)).
|
||||
|
||||
i. For each risk, an owner must be identified. The risk owner and the asset owner may be the same individual.
|
||||
|
||||
i. Once risk owners are identified, they must assess:
|
||||
|
||||
1. Consequences for each combination of threats and vulnerabilities for an individual asset if such a risk materializes.
|
||||
|
||||
1. Likelihood of occurrence of such a risk (i.e. the probability that a threat will exploit the vulnerability of the respective asset).
|
||||
|
||||
1. Criteria for determining consequence and likelihood are defined in Tables 3 and 4.
|
||||
|
||||
i. The risk level is calculated by adding the consequence score and the likelihood score.
|
||||
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| **Consequence** | **Consequence** | **Description** |
|
||||
| **Level** | **Score** | |
|
||||
+=================+=================+==============================================================+
|
||||
| Low | 0 | Loss of confidentiality, integrity, or availability will not |
|
||||
| | | affect the organization's cash flow, legal, or contractual |
|
||||
| | | obligations, or reputation. |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| | | |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| Moderate | 1 | Loss of confidentiality, integrity, or availability may incur|
|
||||
| | | financial cost and has low or moderate impact on the |
|
||||
| | | organization's legal or contractual obligations and/or |
|
||||
| | | reputation. |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| | | |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| High | 2 | Loss of confidentiality, integrity, or availability will have|
|
||||
| | | immediate and or/considerable impact on the organization's |
|
||||
| | | cash flow, operations, legal and contractual obligations,and/|
|
||||
| | | or reputation. |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| | | |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
|
||||
Table 3: Description of Consequence Levels and Criteria
|
||||
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| **Likelihood** | **Likelihood** | **Description** |
|
||||
| **Level** | **Score** | |
|
||||
+=================+=================+==============================================================+
|
||||
| Low | 0 | Either existing security controls are strong and have so far |
|
||||
| | | provided an adequate level of protection, or the probability |
|
||||
| | | of the risk being realized is extremely low. No new incidents|
|
||||
| | | are expected in the future. |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| | | |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| Moderate | 1 | Either existing security controls have most provided an |
|
||||
| | | adequate level of protection or the probability of the risk |
|
||||
| | | being realized is moderate. Some minor incidents may have |
|
||||
| | | occured. New incidents are possible, but not highly likely. |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| | | |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| High | 2 | Either existing security controls are not in place or |
|
||||
| | | ineffective; there is a high probability of the risk being |
|
||||
| | | realized. Incidents have a high likelihood of occuring in the|
|
||||
| | | future. |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
| | | |
|
||||
+-----------------+-----------------+--------------------------------------------------------------+
|
||||
|
||||
Table 4: Description of Likelihood Levels and Criteria
|
||||
|
||||
|
||||
|
||||
b. *Risk Acceptance Criteria*
|
||||
|
||||
i. Risk values 0 through 2 are considered to be acceptable risks.
|
||||
|
||||
i. Risk values 3 and 4 are considered to be unacceptable risks. Unacceptable risks must be treated.
|
||||
|
||||
c. *Risk Treatment*
|
||||
|
||||
i. Risk treatment is implemented through the Risk Treatment Table. All risks from the Risk Assessment Table must be copied to the Risk Treatment Table for disposition, along with treatment options and residual risk. A sample Risk Treatment Table is provided in reference (a).
|
||||
|
||||
i. As part of this risk treatment process, the CEO and/or other company managers shall determine objectives for mitigating or treating risks. All unacceptable risks must be treated. For continuous improvement purposes, company managers may also opt to treat other risks for company assets, even if their risk score is deemed to be acceptable.
|
||||
|
||||
i. Treatment options for risks include the following options:
|
||||
|
||||
1. Selection or development of security control(s).
|
||||
|
||||
1. Transferring the risks to a third party; for example, by purchasing an insurance policy or signing a contract with suppliers or partners.
|
||||
|
||||
1. Avoiding the risk by discontinuing the business activity that causes such risk.
|
||||
|
||||
1. Accepting the risk; this option is permitted only if the selection of other risk treatment options would cost more than the potential impact of the risk being realized.
|
||||
|
||||
i. After selecting a treatment option, the risk owner should estimate the new consequence and likelihood values after the planned controls are implemented.
|
||||
|
||||
a. *Regular Reviews of Risk Assessment and Risk Treatment*
|
||||
|
||||
i. The Risk Assessment Table and Risk Treatment Table must be updated when newly identified risks are identified. At a minimum, this update and review shall be conducted once per year. It is highly recommended that the Risk Assessment and Risk Treatment Table be updated when significant changes occur to the organization, technology, business objectives, or business environment.
|
||||
|
||||
a. *Reporting*
|
||||
|
||||
i. The results of risk assessment and risk treatment, and all subsequent reviews, shall be documented in a Risk Assessment Report.
|
||||
|
||||
The XXX Policy governs X.
|
||||
|
@ -8,6 +8,40 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
a. This policy defines the rules for relationships with the organization’s Information Technology (IT) vendors and partners.
|
||||
|
||||
a. This policy applies to all IT vendors and partners who have the ability to impact the confidentiality, integrity, and availability of the organization’s technology and sensitive information, or who are within the scope of the organization’s information security program.
|
||||
|
||||
a. This policy applies to all employees and contractors that are responsible for the management and oversight of IT vendors and partners of the organization.
|
||||
|
||||
# Background
|
||||
|
||||
a. The overall security of the organization is highly dependent on the security of its contractual relationships with its IT suppliers and partners. This policy defines requirements for effective management and oversight of such suppliers and partners from an information security perspective. The policy prescribes minimum standards a vendor must meet from an information security standpoint, including security clauses, risk assessments, service level agreements, and incident management.
|
||||
|
||||
# References
|
||||
|
||||
a. Information Security Policy
|
||||
|
||||
a. Security Incident Response Policy
|
||||
|
||||
# Policy
|
||||
|
||||
a. IT vendors are prohibited from accessing the organization’s information security assets until a contract containing security controls is agreed to and signed by the appropriate parties.
|
||||
|
||||
a. All IT vendors must comply with the security policies defined and derived from the Information Security Policy (reference (a)).
|
||||
|
||||
a. All security incidents by IT vendors or partners must be documented in accordance with the organization’s Security Incident Response Policy (reference (b)) and immediately forwarded to the Information Security Manager (ISM).
|
||||
|
||||
a. The organization must adhere to the terms of all Service Level Agreements (SLAs) entered into with IT vendors. As terms are updated, and as new ones are entered into, the organization must implement any changes or controls needed to ensure it remains in compliance.
|
||||
|
||||
a. Before entering into a contract and gaining access to the parent organization’s information systems, IT vendors must undergo a risk assessment.
|
||||
|
||||
i. Security risks related to IT vendors and partners must be identified during the risk assessment process.
|
||||
|
||||
i. The risk assessment must identify risks related to information and communication technology, as well as risks related to IT vendor supply chains, to include sub-suppliers.
|
||||
|
||||
a. IT vendors and partners must ensure that organizational records are protected, safeguarded, and disposed of securely. The organization strictly adheres to all applicable legal, regulatory and contractual requirements regarding the collection, processing, and transmission of sensitive data such as Personally-Identifiable Information (PII).
|
||||
|
||||
a. The organization may choose to audit IT vendors and partners to ensure compliance with applicable security policies, as well as legal, regulatory and contractual obligations.
|
||||
|
@ -8,6 +8,44 @@ majorRevisions:
|
||||
comment: Initial document
|
||||
---
|
||||
|
||||
# Overview
|
||||
# Purpose and Scope
|
||||
|
||||
The XXX Policy governs X.
|
||||
a. This policy defines best practices to reduce the risk of data loss/exposure through workstations.
|
||||
|
||||
a. This policy applies to all employees and contractors. Workstation is defined as the collection of all company-owned and personal devices containing company data.
|
||||
|
||||
# Policy
|
||||
|
||||
a. Workstation devices must meet the following criteria:
|
||||
|
||||
i. Operating system must be no more than one generation older than current
|
||||
|
||||
i. Device must be encrypted at rest
|
||||
|
||||
i. Device must be locked when not in use or when employee leaves the workstation
|
||||
|
||||
i. Workstations must be used for authorized business purposes only
|
||||
|
||||
i. Loss or destruction of devices should be reported immediately
|
||||
|
||||
i. Laptops and desktop devices should run the latest version of antivirus software that has been approved by IT
|
||||
|
||||
a. *Desktop & laptop devices*
|
||||
|
||||
i. Employees will be issued a desktop, laptop, or both by the company, based on their job duties. Contractors will provide their own laptops.
|
||||
|
||||
i. Desktops and laptops must operate on macOS or Windows.
|
||||
|
||||
a. *Mobile devices*
|
||||
|
||||
i. Mobile devices must be operated as defined in the Removable Media Policy, Cloud Storage, and Bring Your Own Device Policy.
|
||||
|
||||
i. Mobile devices must operate on iOS or Android.
|
||||
|
||||
i. Company data may only be accessed on mobile devices with Slack and Gmail.
|
||||
|
||||
a. *Removable media*
|
||||
|
||||
i. Removable media must be operated as defined in the Removable Media Policy, Cloud Storage, and Bring Your Own Device Policy.
|
||||
|
||||
i. Removable media is permitted on approved devices as long as it does not conflict with other policies.
|
||||
|
@ -1 +1,3 @@
|
||||
# TODO Describe Procedures
|
||||
# Procedures
|
||||
|
||||
Procedures prescribe specific steps that are taken in response to key events.
|
||||
|
@ -2,12 +2,10 @@ id: "offboard"
|
||||
name: "Offboard User"
|
||||
---
|
||||
|
||||
# Onboarding Steps
|
||||
Resolve this ticket by executing the following steps:
|
||||
|
||||
- [ ] Determine github username and assign to correct Org
|
||||
- [ ] Create Slack account
|
||||
- [ ] Determine and assign IAM role
|
||||
|
||||
# Attach Evidence
|
||||
|
||||
No evidence beyond activity logs within Slack, Github
|
||||
- [ ] Immediately suspend user in SSO
|
||||
- [ ] Append HR termination request e-mail to this ticket
|
||||
- [ ] Look up manually-provisioned applications for this role or user
|
||||
- [ ] Validate access revocation in each
|
||||
- [ ] Append confirmation or revocation to this ticket
|
@ -2,12 +2,11 @@ id: "onboard"
|
||||
name: "Onboard New User"
|
||||
---
|
||||
|
||||
# Onboarding Steps
|
||||
Resolve this ticket by executing the following steps:
|
||||
|
||||
- [ ] Determine github username and assign to correct Org
|
||||
- [ ] Create Slack account
|
||||
- [ ] Determine and assign IAM role
|
||||
|
||||
# Attach Evidence
|
||||
|
||||
No evidence beyond activity logs within Slack, Github
|
||||
- [ ] Append HR add request e-mail to this ticket
|
||||
- [ ] Proactively validate role assignment with manager (see HR request e-mail)
|
||||
- [ ] Add user to default group for the specified role
|
||||
- [ ] Provision any manually-provisioned applications by role
|
||||
- [ ] Append manual provisioning confirmation to this ticket
|
||||
- [ ] Proactively confirm with new user that they can access all provisioned systems
|
@ -1,11 +1,15 @@
|
||||
id: "patch"
|
||||
name: "Apply OS patches"
|
||||
cron: "0 0 1 * * *"
|
||||
cron: "0 0 0 15 * *"
|
||||
---
|
||||
|
||||
# Production Environment
|
||||
# OS Patch Procedure
|
||||
|
||||
- [ ] View patchlevel report in OpenVAS
|
||||
- [ ] Apply patches using Ansible playbooks
|
||||
- [ ] AWS us-west-2
|
||||
- [ ] Reston Datacenter
|
||||
Resolve this ticket by executing the following steps:
|
||||
|
||||
- [ ] Pull the latest scripts from the Ops repository
|
||||
- [ ] Execute `ENV=staging patch-all.sh`
|
||||
- [ ] Inspect output
|
||||
- [ ] Errors? Investigate and resolve
|
||||
- [ ] Execute `ENV=production patch-all.sh`
|
||||
- [ ] Attach log output to this ticket
|
@ -1,13 +1,40 @@
|
||||
id: "workstation"
|
||||
name: "Collect Workstation Details"
|
||||
cron: "0 0 * * * *"
|
||||
cron: "0 0 0 15 4 *"
|
||||
---
|
||||
|
||||
# Workstation Details
|
||||
Resolve this ticket by executing the following steps:
|
||||
|
||||
- [ ] E-mail all users requesting confirmation of drive encryption
|
||||
- [ ] E-mail all users requesting confirmation of antivirus / antimalware configuration
|
||||
- [ ] Send the communications below
|
||||
- [ ] For any email replies, attach content to this ticket
|
||||
- [ ] Validate responses are received from each
|
||||
|
||||
# Insert Evidence
|
||||
|
||||
Insert evidence into the Evidence Vault
|
||||
```
|
||||
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
|
||||
```
|
@ -1,4 +1,4 @@
|
||||
# Compliance Standards
|
||||
# Standards
|
||||
|
||||
All `yaml` files in this directory are assumed to conform to https://github.com/opencontrol/schemas/tree/master/kwalify/standard
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,11 +13,15 @@ html lang=en
|
||||
= javascript
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
document.querySelectorAll('.cron').forEach(function(el) {
|
||||
el.innerHTML = prettyCron.toString(el.innerHTML)
|
||||
el.innerHTML = prettyCron.toString((""+el.innerHTML).trim(),true) // 6-field expressions
|
||||
})
|
||||
})
|
||||
|
||||
function show(name) {
|
||||
if (history.replaceState) {
|
||||
history.replaceState(null, null, '#'+name)
|
||||
}
|
||||
|
||||
var items = document.getElementsByClassName('top-nav')
|
||||
for (var i=0; i<items.length; i++) {
|
||||
var item = items[i]
|
||||
@ -91,13 +95,13 @@ html lang=en
|
||||
div
|
||||
p.heading Active Tickets
|
||||
p.title
|
||||
a target=_blank href="https://github.com/strongdm/comply/issues?q=is%3Aissue+is%3Aopen+label%3Acomply+label%3Aprocess"
|
||||
{{.Stats.ProcessOpen}}
|
||||
a target=_blank href="{{.Links.ProcedureOpen}}"
|
||||
{{.Stats.ProcedureOpen}}
|
||||
.column.has-text-centered
|
||||
div
|
||||
p.heading Oldest Ticket
|
||||
p.title
|
||||
a {{.Stats.ProcessOldestDays}} days
|
||||
a {{.Stats.ProcedureOldestDays}} days
|
||||
.columns.is-vcentered
|
||||
.column.is-one-third
|
||||
div.has-text-centered
|
||||
@ -106,13 +110,13 @@ html lang=en
|
||||
div
|
||||
p.heading Open Requests
|
||||
p.title
|
||||
a target=_blank href="https://github.com/strongdm/comply/issues?q=is%3Aissue+is%3Aopen+label%3Acomply+label%3Aaudit"
|
||||
a target=_blank href="{{.Links.AuditOpen}}"
|
||||
{{.Stats.AuditOpen}}
|
||||
.column.has-text-centered
|
||||
div
|
||||
p.heading Total Requests
|
||||
p.title
|
||||
a target=_blank href="https://github.com/strongdm/comply/issues?q=is%3Aissue+is%3Aclosed+label%3Acomply+label%3Aaudit"
|
||||
a target=_blank href="{{.Links.AuditAll}}"
|
||||
{{.Stats.AuditTotal}}
|
||||
.columns.is-vcentered
|
||||
.column.is-one-third
|
||||
@ -144,7 +148,7 @@ html lang=en
|
||||
h3
|
||||
p
|
||||
strong Policies
|
||||
| govern the behavior of {{.Project.OrganizationName}} employees and contractors.
|
||||
| govern the behavior of {{.Name}} employees and contractors.
|
||||
table.table.is-size-4
|
||||
thead
|
||||
tr
|
||||
@ -220,5 +224,14 @@ html lang=en
|
||||
.content.has-text-centered
|
||||
p {{.Project.OrganizationName}} Confidential 2018
|
||||
= javascript
|
||||
// commented for development
|
||||
show('overview')
|
||||
if (window.location.hash=="") {
|
||||
show('overview')
|
||||
} else {
|
||||
var hashComponents = window.location.hash.split('#')
|
||||
if (hashComponents.length>1) {
|
||||
var destination = hashComponents[1]
|
||||
if (["overview","narratives","policies","procedures","standards"].indexOf(destination) >= 0) {
|
||||
show(destination)
|
||||
}
|
||||
}
|
||||
}
|
94
fixtures/narratives/invalid-control.md
Normal file
94
fixtures/narratives/invalid-control.md
Normal 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.
|
55
fixtures/policies/invalid-access.md
Normal file
55
fixtures/policies/invalid-access.md
Normal file
@ -0,0 +1,55 @@
|
||||
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 person’s job duties. When a user’s 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.
|
39
fixtures/procedures/invalid-workstation.md
Normal file
39
fixtures/procedures/invalid-workstation.md
Normal 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
|
||||
```
|
245
fixtures/standards/invalid-standard.yml
Normal file
245
fixtures/standards/invalid-standard.yml
Normal 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s objectives related to confidentiality
|
||||
C1.2:
|
||||
family: C1
|
||||
name: Confidential Information Disposal
|
||||
description: The entity disposes of confidential information to meet the entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s objectives
|
||||
P1.1:
|
||||
family: P1
|
||||
name: Privacy Notification
|
||||
description: The entity provides notice to data subjects about its privacy practices to meet the entity’s objectives related to privacy. The notice is updated and communicated to data subjects in a timely manner for changes to the entity’s privacy practices, including changes in the use of personal information, to meet the entity’s 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 entity’s objectives related to privacy. The entity’s 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 entity’s 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 entity’s 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 entity’s objectives related to privacy
|
||||
P4.2:
|
||||
family: P4
|
||||
name: Personal Information Retention
|
||||
description: The entity retains personal information consistent with the entity’s objectives related to privacy
|
||||
P4.3:
|
||||
family: P4
|
||||
name: Personal Information Disposal
|
||||
description: The entity securely disposes of personal information to meet the entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s 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 entity’s objectives related to privacy. Corrections and other necessary actions related to identified deficiencies are made or taken in a timely manner
|
73
go.mod
Normal file
73
go.mod
Normal file
@ -0,0 +1,73 @@
|
||||
module github.com/strongdm/comply
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/Clever/gitsem v1.1.0
|
||||
github.com/Microsoft/go-winio v0.5.0 // indirect
|
||||
github.com/aktau/github-release v0.10.0
|
||||
github.com/andygrunwald/go-jira v1.14.0
|
||||
github.com/containerd/containerd v1.5.10 // indirect
|
||||
github.com/containous/go-bindata v1.0.0
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/docker/docker v20.10.9+incompatible
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/github-release/github-release v0.10.0 // indirect
|
||||
github.com/gohugoio/hugo v0.88.1
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 // indirect
|
||||
github.com/joho/godotenv v1.4.0
|
||||
github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc // indirect
|
||||
github.com/kevinburke/rest v0.0.0-20210506044642-5611499aa33c // indirect
|
||||
github.com/manifoldco/promptui v0.8.0
|
||||
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/nanobox-io/golang-scribble v0.0.0-20190309225732-aa3e7c118975
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect
|
||||
github.com/urfave/cli v1.22.5
|
||||
github.com/voxelbrain/goptions v0.0.0-20180630082107-58cddc247ea2 // indirect
|
||||
github.com/xanzy/go-gitlab v0.51.1
|
||||
github.com/yosssi/ace v0.0.5
|
||||
golang.org/x/net v0.0.0-20211005001312-d4b1ae081e3b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
|
||||
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
google.golang.org/genproto v0.0.0-20211005153810-c76a74d43a8e // indirect
|
||||
google.golang.org/grpc v1.41.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/lunixbochs/vtclean v1.0.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/trivago/tgo v1.0.7 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/blang/semver.v1 v1.1.0 // indirect
|
||||
)
|
@ -2,24 +2,34 @@ package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
"github.com/strongdm/comply/internal/gitlab"
|
||||
"github.com/strongdm/comply/internal/jira"
|
||||
"github.com/strongdm/comply/internal/plugin/github"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Version is set by the build system.
|
||||
const Version = "0.0.0-development"
|
||||
var Version = ""
|
||||
|
||||
// Main should be invoked by the main function in the main package.
|
||||
func Main() {
|
||||
@ -32,28 +42,37 @@ func Main() {
|
||||
func newApp() *cli.App {
|
||||
app := cli.NewApp()
|
||||
app.Name = "comply"
|
||||
app.HideVersion = true
|
||||
if Version == "" {
|
||||
app.HideVersion = true
|
||||
}
|
||||
app.Version = Version
|
||||
app.Usage = "policy compliance toolkit"
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
initCommand,
|
||||
beforeCommand(initCommand, notifyVersion),
|
||||
}
|
||||
|
||||
app.Commands = append(app.Commands, beforeCommand(buildCommand, projectMustExist))
|
||||
app.Commands = append(app.Commands, beforeCommand(schedulerCommand, projectMustExist))
|
||||
app.Commands = append(app.Commands, beforeCommand(serveCommand, projectMustExist))
|
||||
app.Commands = append(app.Commands, beforeCommand(syncCommand, projectMustExist))
|
||||
app.Commands = append(app.Commands, beforeCommand(todoCommand, projectMustExist))
|
||||
app.Commands = append(app.Commands, beforeCommand(buildCommand, projectMustExist, notifyVersion))
|
||||
app.Commands = append(app.Commands, beforeCommand(procedureCommand, projectMustExist, notifyVersion))
|
||||
app.Commands = append(app.Commands, beforeCommand(schedulerCommand, projectMustExist, notifyVersion))
|
||||
app.Commands = append(app.Commands, beforeCommand(serveCommand, projectMustExist, notifyVersion))
|
||||
app.Commands = append(app.Commands, beforeCommand(syncCommand, projectMustExist, notifyVersion))
|
||||
app.Commands = append(app.Commands, beforeCommand(todoCommand, projectMustExist, notifyVersion))
|
||||
|
||||
// Plugins
|
||||
github.Register()
|
||||
jira.Register()
|
||||
gitlab.Register()
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func beforeCommand(c cli.Command, bf ...cli.BeforeFunc) cli.Command {
|
||||
c.Before = beforeAll(bf...)
|
||||
if c.Before == nil {
|
||||
c.Before = beforeAll(bf...)
|
||||
} else {
|
||||
c.Before = beforeAll(append(bf, c.Before)...)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
@ -80,7 +99,190 @@ func projectMustExist(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func dockerMustExist(c *cli.Context) error {
|
||||
func ticketingMustBeConfigured(c *cli.Context) error {
|
||||
p := config.Config()
|
||||
if p.Tickets == nil || len(p.Tickets) != 1 {
|
||||
return feedbackError("comply.yml must contain a valid ticketing configuration")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// notifyVersion asynchronously notifies the availability of version updates
|
||||
func notifyVersion(c *cli.Context) error {
|
||||
go func() {
|
||||
defer func() {
|
||||
recover() // suppress panic
|
||||
}()
|
||||
|
||||
r, err := http.Get("http://comply-releases.s3.amazonaws.com/channel/stable/VERSION")
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
// fail silently
|
||||
}
|
||||
|
||||
version := strings.TrimSpace(string(body))
|
||||
|
||||
// only when numeric versions are present
|
||||
firstRune, _ := utf8.DecodeRuneInString(string(body))
|
||||
if unicode.IsDigit(firstRune) && version != Version {
|
||||
// only once every ~10 times
|
||||
if rand.Intn(10) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "a new version of comply is available")
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func pandocMustExist(c *cli.Context) error {
|
||||
eitherMustExistErr := fmt.Errorf("\n\nPlease install either Docker or the pandoc package and re-run `%s`. Find OS-specific pandoc installation instructions at: https://pandoc.org/installing.html", c.Command.Name)
|
||||
|
||||
pandocBinaryExistErr, found, goodVersion, pdfLatex := pandocBinaryMustExist(c)
|
||||
dockerExistErr, inPath, isRunning := dockerMustExist(c)
|
||||
|
||||
config.SetPandoc(pandocBinaryExistErr == nil, dockerExistErr == nil)
|
||||
check := func(b bool) string {
|
||||
if b {
|
||||
return "✔"
|
||||
} else {
|
||||
return "✖"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if pandocBinaryExistErr != nil && dockerExistErr != nil {
|
||||
|
||||
fmt.Printf(`
|
||||
[%s] pandoc binary installed and in PATH
|
||||
[%s] pandoc version compatible
|
||||
[%s] pdflatex binary installed and in PATH
|
||||
[%s] docker binary installed
|
||||
[%s] docker running
|
||||
|
||||
`, check(found), check(goodVersion), check(pdfLatex), check(inPath), check(isRunning))
|
||||
|
||||
return eitherMustExistErr
|
||||
}
|
||||
|
||||
// if we don't have pandoc, but we do have docker, execute a pull
|
||||
if !pandocImageExists(context.Background()) && ((pandocBinaryExistErr != nil && dockerExistErr == nil) || config.WhichPandoc() == config.UseDocker) {
|
||||
canPullPandoc := strings.TrimSpace(strings.ToLower(os.Getenv("COMPLY_USE_LOCAL_PANDOC"))) != "true"
|
||||
if canPullPandoc {
|
||||
fmt.Println("Pulling docker image")
|
||||
dockerPull(c)
|
||||
} else {
|
||||
return fmt.Errorf("Local Pandoc not found. Please set COMPLY_USE_LOCAL_PANDOC to false")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var pandocBinaryMustExist = func(c *cli.Context) (e error, found, goodVersion, pdfLatex bool) {
|
||||
cmd := exec.Command("pandoc", "-v")
|
||||
outputRaw, err := cmd.Output()
|
||||
|
||||
e = nil
|
||||
found = false
|
||||
goodVersion = false
|
||||
pdfLatex = false
|
||||
|
||||
if err != nil {
|
||||
e = errors.Wrap(err, "error calling pandoc")
|
||||
} else {
|
||||
found = true
|
||||
goodVersion = true
|
||||
output := strings.TrimSpace((string(outputRaw)))
|
||||
versionErr := errors.New("cannot determine pandoc version")
|
||||
if !strings.HasPrefix(output, "pandoc") {
|
||||
e = versionErr
|
||||
goodVersion = false
|
||||
} else {
|
||||
re := regexp.MustCompile(`pandoc (\d+)\.(\d+)`)
|
||||
result := re.FindStringSubmatch(output)
|
||||
if len(result) != 3 {
|
||||
e = versionErr
|
||||
goodVersion = false
|
||||
} else {
|
||||
major, err := strconv.Atoi(result[1])
|
||||
if err != nil {
|
||||
e = versionErr
|
||||
goodVersion = false
|
||||
}
|
||||
minor, err := strconv.Atoi(result[2])
|
||||
if err != nil {
|
||||
e = versionErr
|
||||
goodVersion = false
|
||||
}
|
||||
if major < 2 || minor < 1 {
|
||||
e = errors.New("pandoc 2.1 or greater required")
|
||||
goodVersion = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pdflatex must also be present
|
||||
cmd = exec.Command("pdflatex", "--version")
|
||||
outputRaw, err = cmd.Output()
|
||||
if err != nil {
|
||||
e = errors.Wrap(err, "error calling pdflatex")
|
||||
} else if !strings.Contains(string(outputRaw), "TeX") {
|
||||
e = errors.New("pdflatex is required")
|
||||
} else {
|
||||
pdfLatex = true
|
||||
}
|
||||
|
||||
return e, found, goodVersion, pdfLatex
|
||||
}
|
||||
|
||||
var dockerMustExist = func(c *cli.Context) (e error, inPath, isRunning bool) {
|
||||
dockerErr := fmt.Errorf("Docker must be available in order to run `%s`", c.Command.Name)
|
||||
|
||||
inPath = true
|
||||
cmd := exec.Command("docker", "--version")
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
inPath = false
|
||||
}
|
||||
|
||||
isRunning = true
|
||||
ctx := context.Background()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
isRunning = false
|
||||
return dockerErr, inPath, isRunning
|
||||
}
|
||||
|
||||
_, err = cli.Ping(ctx)
|
||||
if err != nil {
|
||||
isRunning = false
|
||||
return dockerErr, inPath, isRunning
|
||||
}
|
||||
|
||||
return nil, inPath, isRunning
|
||||
}
|
||||
|
||||
var pandocImageExists = func(ctx context.Context) bool {
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
options := types.ImageListOptions{All: true}
|
||||
imageList, err := cli.ImageList(ctx, options)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, image := range imageList {
|
||||
if len(image.RepoTags) > 0 && strings.Contains(image.RepoTags[0], "strongdm/pandoc:edge") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var dockerPull = func(c *cli.Context) error {
|
||||
dockerErr := fmt.Errorf("Docker must be available in order to run `%s`", c.Command.Name)
|
||||
|
||||
ctx := context.Background()
|
||||
@ -89,28 +291,79 @@ func dockerMustExist(c *cli.Context) error {
|
||||
return dockerErr
|
||||
}
|
||||
|
||||
r, err := cli.ImagePull(ctx, "strongdm/pandoc:latest", types.ImagePullOptions{})
|
||||
if err != nil {
|
||||
return dockerErr
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
|
||||
go func() {
|
||||
// if docker IO takes more than N seconds, notify user we're (likely) downloading the pandoc image
|
||||
longishPull := time.After(time.Second * 6)
|
||||
longishPull := time.After(time.Second * 5)
|
||||
|
||||
select {
|
||||
case <-longishPull:
|
||||
fmt.Println("Downloading strongdm/pandoc image (this may take sometime) ...")
|
||||
fmt.Print("Pulling strongdm/pandoc:edge Docker image (this will take some time) ")
|
||||
|
||||
go func() {
|
||||
for {
|
||||
fmt.Print(".")
|
||||
select {
|
||||
case <-done:
|
||||
fmt.Print(" done.\n")
|
||||
return
|
||||
default:
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
case <-done:
|
||||
// in this case, the docker pull was quick -- suggesting we already have the container
|
||||
}
|
||||
}()
|
||||
|
||||
r, err := cli.ImagePull(ctx, "strongdm/pandoc:edge", types.ImagePullOptions{})
|
||||
if err != nil {
|
||||
return dockerErr
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
// hold function open until all docker IO is complete
|
||||
io.Copy(ioutil.Discard, r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanContainers(c *cli.Context) error {
|
||||
ctx := context.Background()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
// no Docker? nothing to clean.
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = cli.Ping(ctx)
|
||||
if err != nil {
|
||||
// no Docker? nothing to clean.
|
||||
return nil
|
||||
}
|
||||
|
||||
containers, err := cli.ContainerList(ctx, types.ContainerListOptions{All: true})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error listing containers during cleanup")
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
// assume this container was leftover from previous aborted run
|
||||
if strings.HasPrefix(c.Image, "strongdm/pandoc:edge") {
|
||||
d := time.Second * 2
|
||||
err = cli.ContainerStop(ctx, c.ID, &d)
|
||||
if err != nil {
|
||||
fmt.Printf("Unable to stop container ID %s\n", c.ID)
|
||||
}
|
||||
|
||||
err = cli.ContainerRemove(ctx, c.ID, types.ContainerRemoveOptions{Force: true})
|
||||
if err != nil {
|
||||
fmt.Printf("Unable to remove container ID %s, please attempt manual removal\n", c.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
189
internal/cli/app_test.go
Normal file
189
internal/cli/app_test.go
Normal file
@ -0,0 +1,189 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/strongdm/comply/internal/util"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type PandocMustExist struct{}
|
||||
|
||||
func TestPandocMustExist(t *testing.T) {
|
||||
util.ExecuteTests(t, reflect.TypeOf(PandocMustExist{}), beforeEach, nil)
|
||||
}
|
||||
|
||||
func beforeEach() {
|
||||
util.MockConfig()
|
||||
}
|
||||
|
||||
func (tg PandocMustExist) WhenBinaryExists(t *testing.T) {
|
||||
dockerPullCalled := false
|
||||
|
||||
pandocBinaryMustExist = func(c *cli.Context) (e error, found, goodVersion, pdfLatex bool) {
|
||||
return nil, true, true, true
|
||||
}
|
||||
|
||||
dockerMustExist = func(c *cli.Context) (e error, inPath bool, isRunning bool) {
|
||||
return errors.New("docker doesn't exist"), false, false
|
||||
}
|
||||
|
||||
pandocImageExists = func(ctx context.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
dockerPull = func(c *cli.Context) error {
|
||||
dockerPullCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
pandocMustExist(&cli.Context{})
|
||||
|
||||
if dockerPullCalled != false {
|
||||
t.Fatal("Docker was pulled")
|
||||
}
|
||||
}
|
||||
|
||||
func (tg PandocMustExist) WhenImageExists(t *testing.T) {
|
||||
dockerPullCalled := false
|
||||
|
||||
pandocBinaryMustExist = func(c *cli.Context) (e error, found, goodVersion, pdfLatex bool) {
|
||||
return errors.New("binary doesn't exist"), false, true, true
|
||||
}
|
||||
|
||||
dockerMustExist = func(c *cli.Context) (e error, inPath bool, isRunning bool) {
|
||||
return errors.New("docker doesn't exist"), false, false
|
||||
}
|
||||
|
||||
pandocImageExists = func(ctx context.Context) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
dockerPull = func(c *cli.Context) error {
|
||||
dockerPullCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
pandocMustExist(&cli.Context{})
|
||||
|
||||
if dockerPullCalled != false {
|
||||
t.Fatal("Docker was pulled")
|
||||
}
|
||||
}
|
||||
|
||||
func (tg PandocMustExist) WhenBinaryAndImageDontExists(t *testing.T) {
|
||||
dockerPullCalled := false
|
||||
|
||||
pandocBinaryMustExist = func(c *cli.Context) (e error, found, goodVersion, pdfLatex bool) {
|
||||
return errors.New("binary doesn't exist"), false, false, false
|
||||
}
|
||||
|
||||
dockerMustExist = func(c *cli.Context) (e error, inPath bool, isRunning bool) {
|
||||
return nil, true, false
|
||||
}
|
||||
|
||||
pandocImageExists = func(ctx context.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
dockerPull = func(c *cli.Context) error {
|
||||
dockerPullCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
pandocMustExist(&cli.Context{})
|
||||
|
||||
if dockerPullCalled != true {
|
||||
t.Fatal("Docker wasn't pulled")
|
||||
}
|
||||
}
|
||||
|
||||
func (tg PandocMustExist) WhenCannotPullPandoc(t *testing.T) {
|
||||
dockerPullCalled := false
|
||||
|
||||
pandocBinaryMustExist = func(c *cli.Context) (e error, found, goodVersion, pdfLatex bool) {
|
||||
return errors.New("binary doesn't exist"), false, false, false
|
||||
}
|
||||
|
||||
dockerMustExist = func(c *cli.Context) (e error, inPath bool, isRunning bool) {
|
||||
return errors.New("docker doesn't exist"), false, false
|
||||
}
|
||||
|
||||
pandocImageExists = func(ctx context.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
dockerPull = func(c *cli.Context) error {
|
||||
dockerPullCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
pandocMustExist(&cli.Context{})
|
||||
|
||||
if dockerPullCalled != false {
|
||||
t.Fatal("Docker was pulled")
|
||||
}
|
||||
}
|
||||
|
||||
func (tg PandocMustExist) WhenMustUseLocalPandoc(t *testing.T) {
|
||||
os.Setenv("COMPLY_USE_LOCAL_PANDOC", "true")
|
||||
dockerPullCalled := false
|
||||
|
||||
pandocBinaryMustExist = func(c *cli.Context) (e error, found, goodVersion, pdfLatex bool) {
|
||||
return errors.New("binary doesn't exist"), false, false, false
|
||||
}
|
||||
|
||||
dockerMustExist = func(c *cli.Context) (e error, inPath bool, isRunning bool) {
|
||||
return errors.New("docker doesn't exist"), false, false
|
||||
}
|
||||
|
||||
pandocImageExists = func(ctx context.Context) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
dockerPull = func(c *cli.Context) error {
|
||||
dockerPullCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
pandocMustExist(&cli.Context{})
|
||||
|
||||
if dockerPullCalled != false {
|
||||
t.Fatal("Docker was pulled")
|
||||
}
|
||||
|
||||
os.Clearenv()
|
||||
}
|
||||
|
||||
func (tg PandocMustExist) WhenPandocDontExistsAndCannotPull(t *testing.T) {
|
||||
os.Setenv("COMPLY_USE_LOCAL_PANDOC", "true")
|
||||
dockerPullCalled := false
|
||||
|
||||
pandocBinaryMustExist = func(c *cli.Context) (e error, found, goodVersion, pdfLatex bool) {
|
||||
return errors.New("binary doesn't exist"), false, false, false
|
||||
}
|
||||
|
||||
dockerMustExist = func(c *cli.Context) (e error, inPath bool, isRunning bool) {
|
||||
return nil, true, false
|
||||
}
|
||||
|
||||
pandocImageExists = func(ctx context.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
dockerPull = func(c *cli.Context) error {
|
||||
dockerPullCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
pandocMustExist(&cli.Context{})
|
||||
|
||||
if dockerPullCalled != false {
|
||||
t.Fatal("Docker was pulled")
|
||||
}
|
||||
os.Clearenv()
|
||||
}
|
@ -10,14 +10,8 @@ var buildCommand = cli.Command{
|
||||
Name: "build",
|
||||
ShortName: "b",
|
||||
Usage: "generate a static website summarizing the compliance program",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "live, l",
|
||||
Usage: "rebuild static site after filesystem changes",
|
||||
},
|
||||
},
|
||||
Action: buildAction,
|
||||
Before: beforeAll(dockerMustExist),
|
||||
Action: buildAction,
|
||||
Before: beforeAll(pandocMustExist, cleanContainers),
|
||||
}
|
||||
|
||||
func buildAction(c *cli.Context) error {
|
||||
|
@ -16,6 +16,14 @@ import (
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
const whatNow = `Next steps:
|
||||
|
||||
* Customize this directory using a text editor ('cat TODO.md' for ideas)
|
||||
* Try 'comply build' and 'comply serve'
|
||||
* View output/index.html
|
||||
* Add this directory to source control
|
||||
`
|
||||
|
||||
var initCommand = cli.Command{
|
||||
Name: "init",
|
||||
Usage: "initialize a new compliance repository (interactive)",
|
||||
@ -56,7 +64,7 @@ func initAction(c *cli.Context) error {
|
||||
}
|
||||
|
||||
prompt = promptui.Prompt{
|
||||
Label: "PDF Filename Prefix",
|
||||
Label: "PDF Filename Prefix (no spaces, no trailing separator)",
|
||||
Default: strings.Split(name, " ")[0],
|
||||
Validate: noSpaces,
|
||||
}
|
||||
@ -88,9 +96,11 @@ func initAction(c *cli.Context) error {
|
||||
panic("unrecognized selection")
|
||||
}
|
||||
|
||||
fmt.Printf("\nComply relies on your ticketing system for optional procedure tracking. You can always come back and enable this integration later.\n\n\n")
|
||||
|
||||
chooser = promptui.Select{
|
||||
Label: "Ticket System",
|
||||
Items: []string{"Github", "JIRA"},
|
||||
Items: []string{"GitHub", "Jira", "GitLab", "None"},
|
||||
}
|
||||
|
||||
choice, _, err = chooser.Run()
|
||||
@ -99,40 +109,59 @@ func initAction(c *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ticketing := model.Github
|
||||
var tickets map[string]interface{}
|
||||
ticketing := model.GitHub
|
||||
|
||||
switch choice {
|
||||
case 0:
|
||||
ticketing = model.Github
|
||||
ticketing = model.GitHub
|
||||
case 1:
|
||||
ticketing = model.JIRA
|
||||
ticketing = model.Jira
|
||||
case 2:
|
||||
ticketing = model.GitLab
|
||||
default:
|
||||
panic("unrecognized selection")
|
||||
ticketing = model.NoTickets
|
||||
}
|
||||
|
||||
ticketConfig := make(map[string]string)
|
||||
|
||||
plugin := model.GetPlugin(ticketing)
|
||||
ticketPrompts := plugin.Prompts()
|
||||
for k, prompt := range ticketPrompts {
|
||||
p := promptui.Prompt{
|
||||
Label: prompt,
|
||||
Validate: atLeast(2),
|
||||
if ticketing != model.NoTickets {
|
||||
chooser = promptui.Select{
|
||||
Label: "Configure ticketing system?",
|
||||
Items: []string{fmt.Sprintf("Configure %s now", string(ticketing)), "Configure later (via comply.yml)"},
|
||||
}
|
||||
|
||||
v, err := p.Run()
|
||||
choice, _, err = chooser.Run()
|
||||
if err != nil {
|
||||
fmt.Printf("Prompt failed: %v\n", err)
|
||||
fmt.Printf("Prompt failed %v\n", err)
|
||||
return err
|
||||
}
|
||||
ticketConfig[k] = v
|
||||
|
||||
tickets = make(map[string]interface{})
|
||||
ticketConfig := make(map[string]string)
|
||||
tickets[string(ticketing)] = ticketConfig
|
||||
|
||||
if choice == 0 {
|
||||
plugin := model.GetPlugin(ticketing)
|
||||
ticketPrompts := plugin.Prompts()
|
||||
for k, prompt := range ticketPrompts {
|
||||
p := promptui.Prompt{
|
||||
Label: prompt,
|
||||
Validate: atLeast(2),
|
||||
}
|
||||
|
||||
v, err := p.Run()
|
||||
if err != nil {
|
||||
fmt.Printf("Prompt failed: %v\n", err)
|
||||
return err
|
||||
}
|
||||
ticketConfig[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p := config.Project{}
|
||||
p.Name = name
|
||||
p.FilePrefix = prefix
|
||||
p.Tickets = make(map[string]interface{})
|
||||
p.Tickets[string(ticketing)] = ticketConfig
|
||||
p.Tickets = tickets
|
||||
|
||||
x, _ := yaml.Marshal(&p)
|
||||
err = ioutil.WriteFile(filepath.Join(config.ProjectRoot(), "comply.yml"), x, os.FileMode(0644))
|
||||
@ -140,14 +169,17 @@ func initAction(c *cli.Context) error {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
err = theme.SaveTo(themeName, config.ProjectRoot())
|
||||
replace := make(map[string]string)
|
||||
replace["Name"] = p.Name
|
||||
|
||||
err = theme.SaveTo(themeName, replace, config.ProjectRoot())
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
success := fmt.Sprintf("%s Compliance initialized successfully", name)
|
||||
fmt.Println(strings.Repeat("=", len(success)+2))
|
||||
fmt.Printf("%s %s\n", promptui.IconGood, success)
|
||||
success := fmt.Sprintf("%s Compliance initialized successfully!", name)
|
||||
fmt.Printf("%s %s\n\n", promptui.IconGood, success)
|
||||
fmt.Println(whatNow)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
53
internal/cli/procedure.go
Normal file
53
internal/cli/procedure.go
Normal file
@ -0,0 +1,53 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var procedureCommand = cli.Command{
|
||||
Name: "procedure",
|
||||
ShortName: "proc",
|
||||
Usage: "create ticket by procedure ID",
|
||||
ArgsUsage: "procedureID",
|
||||
Action: procedureAction,
|
||||
Before: beforeAll(projectMustExist, ticketingMustBeConfigured),
|
||||
}
|
||||
|
||||
func procedureAction(c *cli.Context) error {
|
||||
procedures, err := model.ReadProcedures()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.NArg() != 1 {
|
||||
return cli.NewExitError("provide a procedure ID", 1)
|
||||
}
|
||||
|
||||
procedureID := c.Args().First()
|
||||
|
||||
ts, err := config.Config().TicketSystem()
|
||||
if err != nil {
|
||||
return cli.NewExitError("error in ticket system configuration", 1)
|
||||
}
|
||||
|
||||
tp := model.GetPlugin(model.TicketSystem(ts))
|
||||
|
||||
for _, procedure := range procedures {
|
||||
if procedure.ID == procedureID {
|
||||
err = tp.Create(&model.Ticket{
|
||||
Name: procedure.Name,
|
||||
Body: fmt.Sprintf("%s\n\n\n---\nProcedure-ID: %s", procedure.Body, procedure.ID),
|
||||
}, []string{"comply", "comply-procedure"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return cli.NewExitError(fmt.Sprintf("unknown procedure ID: %s", procedureID), 1)
|
||||
}
|
@ -9,7 +9,7 @@ var schedulerCommand = cli.Command{
|
||||
Name: "scheduler",
|
||||
Usage: "create tickets based on procedure schedule",
|
||||
Action: schedulerAction,
|
||||
Before: projectMustExist,
|
||||
Before: beforeAll(projectMustExist, ticketingMustBeConfigured),
|
||||
}
|
||||
|
||||
func schedulerAction(c *cli.Context) error {
|
||||
|
@ -1,21 +1,29 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/render"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var serveCommand = cli.Command{
|
||||
Name: "serve",
|
||||
Usage: "live updating version of the build command",
|
||||
Name: "serve",
|
||||
Usage: "live updating version of the build command",
|
||||
Flags: []cli.Flag{
|
||||
cli.IntFlag{
|
||||
Name: "port",
|
||||
Value: 4000,
|
||||
Destination: &render.ServePort,
|
||||
},
|
||||
},
|
||||
Action: serveAction,
|
||||
Before: beforeAll(dockerMustExist),
|
||||
Before: beforeAll(pandocMustExist, cleanContainers),
|
||||
}
|
||||
|
||||
func serveAction(c *cli.Context) error {
|
||||
err := render.Build("output", true)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "serve failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@ -9,11 +10,16 @@ var syncCommand = cli.Command{
|
||||
Name: "sync",
|
||||
Usage: "sync ticket status to local cache",
|
||||
Action: syncAction,
|
||||
Before: projectMustExist,
|
||||
Before: beforeAll(projectMustExist, ticketingMustBeConfigured),
|
||||
}
|
||||
|
||||
func syncAction(c *cli.Context) error {
|
||||
tp := model.GetPlugin(model.Github)
|
||||
ts, err := config.Config().TicketSystem()
|
||||
if err != nil {
|
||||
return cli.NewExitError("error in ticket system configuration", 1)
|
||||
}
|
||||
|
||||
tp := model.GetPlugin(model.TicketSystem(ts))
|
||||
tickets, err := tp.FindByTagName("comply")
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1,6 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -10,15 +11,54 @@ import (
|
||||
|
||||
var projectRoot string
|
||||
|
||||
var dockerAvailable, pandocAvailable bool
|
||||
|
||||
const (
|
||||
Jira = "jira"
|
||||
GitHub = "github"
|
||||
GitLab = "gitlab"
|
||||
NoTickets = "none"
|
||||
)
|
||||
|
||||
const (
|
||||
// UseDocker invokes pandoc within Docker
|
||||
UseDocker = "docker"
|
||||
// UsePandoc invokes pandoc directly
|
||||
UsePandoc = "pandoc"
|
||||
)
|
||||
|
||||
// SetProjectRoot is used by the test suite.
|
||||
func SetProjectRoot(dir string) {
|
||||
projectRoot = dir
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
Name string `yaml:"name"`
|
||||
FilePrefix string `yaml:"filePrefix"`
|
||||
Tickets map[string]interface{} `yaml:"tickets"`
|
||||
Name string `yaml:"name"`
|
||||
Pandoc string `yaml:"pandoc,omitempty"`
|
||||
FilePrefix string `yaml:"filePrefix"`
|
||||
Tickets map[string]interface{} `yaml:"tickets"`
|
||||
ApprovedBranch string `yaml:"approvedBranch"`
|
||||
}
|
||||
|
||||
// SetPandoc records pandoc availability during initialization
|
||||
func SetPandoc(pandoc bool, docker bool) {
|
||||
pandocAvailable = pandoc
|
||||
dockerAvailable = docker
|
||||
}
|
||||
|
||||
// WhichPandoc indicates which pandoc invocation path should be used
|
||||
func WhichPandoc() string {
|
||||
cfg := Config()
|
||||
if cfg.Pandoc == UsePandoc {
|
||||
return UsePandoc
|
||||
}
|
||||
if cfg.Pandoc == UseDocker {
|
||||
return UseDocker
|
||||
}
|
||||
if pandocAvailable {
|
||||
return UsePandoc
|
||||
}
|
||||
return UseDocker
|
||||
}
|
||||
|
||||
// YAML is the parsed contents of ProjectRoot()/config.yml.
|
||||
@ -42,14 +82,14 @@ 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 {
|
||||
panic("unable to load config.yml: " + err.Error())
|
||||
}
|
||||
yaml.Unmarshal(cfgBytes, &p)
|
||||
return p
|
||||
return &p
|
||||
}
|
||||
|
||||
// ProjectRoot is the fully-qualified path to the root directory.
|
||||
@ -64,3 +104,29 @@ func ProjectRoot() string {
|
||||
|
||||
return projectRoot
|
||||
}
|
||||
|
||||
// TicketSystem indicates the type of the configured ticket system
|
||||
func (p *Project) TicketSystem() (string, error) {
|
||||
if len(p.Tickets) > 1 {
|
||||
return NoTickets, errors.New("multiple ticket systems configured")
|
||||
}
|
||||
|
||||
for k := range p.Tickets {
|
||||
switch k {
|
||||
case GitHub:
|
||||
return GitHub, nil
|
||||
case Jira:
|
||||
return Jira, nil
|
||||
case GitLab:
|
||||
return GitLab, nil
|
||||
case NoTickets:
|
||||
return NoTickets, nil
|
||||
default:
|
||||
// explicit error for this case
|
||||
return "", errors.New("unrecognized ticket system configured")
|
||||
}
|
||||
}
|
||||
|
||||
// no ticket block configured
|
||||
return NoTickets, nil
|
||||
}
|
||||
|
218
internal/gitlab/gitlab.go
Normal file
218
internal/gitlab/gitlab.go
Normal file
@ -0,0 +1,218 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
const (
|
||||
cfgDomain = "domain"
|
||||
cfgToken = "token"
|
||||
cfgRepo = "repo"
|
||||
)
|
||||
|
||||
var prompts = map[string]string{
|
||||
cfgDomain: "Fully Qualified GitLab Domain",
|
||||
cfgToken: "GitLab Token",
|
||||
cfgRepo: "GitLab Repository",
|
||||
}
|
||||
|
||||
// Prompts are human-readable configuration element names
|
||||
func (g *gitlabPlugin) Prompts() map[string]string {
|
||||
return prompts
|
||||
}
|
||||
|
||||
// Register causes the Github plugin to register itself
|
||||
func Register() {
|
||||
model.Register(model.GitLab, &gitlabPlugin{})
|
||||
}
|
||||
|
||||
type gitlabPlugin struct {
|
||||
domain string
|
||||
token string
|
||||
reponame string
|
||||
|
||||
clientMu sync.Mutex
|
||||
client *gitlab.Client
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) api() *gitlab.Client {
|
||||
g.clientMu.Lock()
|
||||
defer g.clientMu.Unlock()
|
||||
if g.client == nil {
|
||||
// get go-gitlab client
|
||||
// TODO: see if it's necessary to verify the error
|
||||
gl, _ := gitlab.NewClient(g.token, gitlab.WithBaseURL(g.domain))
|
||||
g.client = gl
|
||||
}
|
||||
return g.client
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) Get(ID string) (*model.Ticket, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) Configured() bool {
|
||||
return g.reponame != "" && g.token != ""
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) Links() model.TicketLinks {
|
||||
links := model.TicketLinks{}
|
||||
links.AuditAll = fmt.Sprintf("%s/%s/issues?scope=all&utf8=✓&state=all&label_name[]=comply-audit", g.domain, g.reponame)
|
||||
links.AuditOpen = fmt.Sprintf("%s/%s/issues?scope=all&utf8=✓&state=opened&label_name[]=comply-audit", g.domain, g.reponame)
|
||||
links.ProcedureAll = fmt.Sprintf("%s/%s/issues?scope=all&utf8=✓&state=all&label_name[]=comply-procedure", g.domain, g.reponame)
|
||||
links.ProcedureOpen = fmt.Sprintf("%s/%s/issues?scope=all&utf8=✓&state=opened&label_name[]=comply-procedure", g.domain, g.reponame)
|
||||
return links
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) Configure(cfg map[string]interface{}) error {
|
||||
var err error
|
||||
|
||||
if g.domain, err = getCfg(cfg, cfgDomain); err != nil {
|
||||
return err
|
||||
}
|
||||
if g.token, err = getCfg(cfg, cfgToken); err != nil {
|
||||
return err
|
||||
}
|
||||
if g.reponame, err = getCfg(cfg, cfgRepo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getCfg(cfg map[string]interface{}, k string) (string, error) {
|
||||
v, ok := cfg[k]
|
||||
if !ok {
|
||||
return "", errors.New("Missing key: " + k)
|
||||
}
|
||||
|
||||
vS, ok := v.(string)
|
||||
if !ok {
|
||||
return "", errors.New("Malformatted key: " + k)
|
||||
}
|
||||
return vS, nil
|
||||
}
|
||||
|
||||
func getProjectIssues(g *gitlabPlugin, options *gitlab.ListProjectIssuesOptions) ([]*gitlab.Issue, error) {
|
||||
issues := []*gitlab.Issue{}
|
||||
options.Page = 1
|
||||
|
||||
for {
|
||||
pageIssues, resp, err := g.api().Issues.ListProjectIssues(g.reponame, options)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error retreiving issues from gitlab")
|
||||
}
|
||||
|
||||
issues = append(issues, pageIssues...)
|
||||
|
||||
if resp.CurrentPage >= resp.TotalPages {
|
||||
break
|
||||
}
|
||||
options.Page = resp.NextPage
|
||||
}
|
||||
|
||||
return issues, nil
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) FindOpen() ([]*model.Ticket, error) {
|
||||
options := &gitlab.ListProjectIssuesOptions{
|
||||
State: gitlab.String("opened"),
|
||||
}
|
||||
|
||||
issues, err := getProjectIssues(g, options)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error during FindOpen")
|
||||
}
|
||||
|
||||
return toTickets(issues), nil
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) FindByTag(name, value string) ([]*model.Ticket, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) FindByTagName(name string) ([]*model.Ticket, error) {
|
||||
options := &gitlab.ListProjectIssuesOptions{
|
||||
State: gitlab.String("all"),
|
||||
Labels: []string{name},
|
||||
}
|
||||
|
||||
issues, err := getProjectIssues(g, options)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error during FindByTagName")
|
||||
}
|
||||
|
||||
return toTickets(issues), nil
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) LinkFor(t *model.Ticket) string {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) Create(ticket *model.Ticket, labels []string) error {
|
||||
l := gitlab.Labels(labels)
|
||||
options := &gitlab.CreateIssueOptions{
|
||||
Title: gitlab.String(ticket.Name),
|
||||
Description: gitlab.String(ticket.Body),
|
||||
Labels: l,
|
||||
}
|
||||
_, _, err := g.api().Issues.CreateIssue(g.reponame, options)
|
||||
return err
|
||||
}
|
||||
|
||||
func toTickets(issues []*gitlab.Issue) []*model.Ticket {
|
||||
var tickets []*model.Ticket
|
||||
for _, i := range issues {
|
||||
tickets = append(tickets, toTicket(i))
|
||||
}
|
||||
return tickets
|
||||
}
|
||||
|
||||
func toTicket(i *gitlab.Issue) *model.Ticket {
|
||||
t := &model.Ticket{Attributes: make(map[string]interface{})}
|
||||
t.ID = strconv.Itoa(i.ID)
|
||||
t.Name = i.Title
|
||||
t.Body = i.Description
|
||||
t.CreatedAt = i.CreatedAt
|
||||
t.State = toState(i.State)
|
||||
|
||||
for _, l := range i.Labels {
|
||||
if l == "audit" {
|
||||
t.SetBool("comply-audit")
|
||||
}
|
||||
if l == "procedure" {
|
||||
t.SetBool("comply-procedure")
|
||||
}
|
||||
|
||||
// seems redundant, but fixes a bug the other two labels introduce
|
||||
// whereby open comply tickets aren't properly accounted for in the UI
|
||||
if l == "comply-audit" {
|
||||
t.SetBool("comply-audit")
|
||||
}
|
||||
if l == "comply-procedure" {
|
||||
t.SetBool("comply-procedure")
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func toState(state string) model.TicketState {
|
||||
switch state {
|
||||
case "closed":
|
||||
return model.Closed
|
||||
}
|
||||
return model.Open
|
||||
}
|
||||
|
||||
func ss(s *string) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return *s
|
||||
}
|
9
internal/gitlab/gitlab_test.go
Normal file
9
internal/gitlab/gitlab_test.go
Normal file
@ -0,0 +1,9 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGitlab(t *testing.T) {
|
||||
createOne()
|
||||
}
|
193
internal/jira/jira.go
Normal file
193
internal/jira/jira.go
Normal file
@ -0,0 +1,193 @@
|
||||
package jira
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
|
||||
jira "github.com/andygrunwald/go-jira"
|
||||
)
|
||||
|
||||
const (
|
||||
cfgUsername = "username"
|
||||
cfgPassword = "password"
|
||||
cfgURL = "url"
|
||||
cfgProject = "project"
|
||||
cfgTaskType = "taskType"
|
||||
)
|
||||
|
||||
var prompts = map[string]string{
|
||||
cfgUsername: "Jira Username",
|
||||
cfgPassword: "Jira Password",
|
||||
cfgURL: "Jira URL",
|
||||
cfgProject: "Jira Project Code",
|
||||
cfgTaskType: "Jira Task Type",
|
||||
}
|
||||
|
||||
// Prompts are human-readable configuration element names
|
||||
func (j *jiraPlugin) Prompts() map[string]string {
|
||||
return prompts
|
||||
}
|
||||
|
||||
// Register causes the Github plugin to register itself
|
||||
func Register() {
|
||||
model.Register(model.Jira, &jiraPlugin{})
|
||||
}
|
||||
|
||||
type jiraPlugin struct {
|
||||
username string
|
||||
password string
|
||||
url string
|
||||
project string
|
||||
taskType string
|
||||
|
||||
clientMu sync.Mutex
|
||||
client *jira.Client
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) api() *jira.Client {
|
||||
j.clientMu.Lock()
|
||||
defer j.clientMu.Unlock()
|
||||
|
||||
if j.client == nil {
|
||||
tp := jira.BasicAuthTransport{
|
||||
Username: j.username,
|
||||
Password: j.password,
|
||||
}
|
||||
|
||||
client, _ := jira.NewClient(tp.Client(), j.url)
|
||||
j.client = client
|
||||
}
|
||||
return j.client
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) Get(ID string) (*model.Ticket, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) Configured() bool {
|
||||
return j.username != "" && j.password != "" && j.url != "" && j.project != "" && j.taskType != ""
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) Links() model.TicketLinks {
|
||||
links := model.TicketLinks{}
|
||||
links.ProcedureAll = fmt.Sprintf("%s/issues/?jql=labels+=+comply-procedure", j.url)
|
||||
links.ProcedureOpen = fmt.Sprintf("%s/issues/?jql=labels+=+comply-procedure+AND+resolution+=+Unresolved", j.url)
|
||||
// links.AuditAll = fmt.Sprintf("%s/issues?q=is%3Aissue+is%3Aopen+label%3Acomply+label%3Aaudit", j.url)
|
||||
// links.AuditOpen = fmt.Sprintf("%s/issues?q=is%3Aissue+is%3Aopen+label%3Acomply+label%3Aaudit", j.url)
|
||||
return links
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) Configure(cfg map[string]interface{}) error {
|
||||
var err error
|
||||
|
||||
if j.username, err = getCfg(cfg, cfgUsername); err != nil {
|
||||
return err
|
||||
}
|
||||
if j.password, err = getCfg(cfg, cfgPassword); err != nil {
|
||||
return err
|
||||
}
|
||||
if j.url, err = getCfg(cfg, cfgURL); err != nil {
|
||||
return err
|
||||
}
|
||||
if j.project, err = getCfg(cfg, cfgProject); err != nil {
|
||||
return err
|
||||
}
|
||||
if j.taskType, err = getCfg(cfg, cfgTaskType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getCfg(cfg map[string]interface{}, k string) (string, error) {
|
||||
v, ok := cfg[k]
|
||||
if !ok {
|
||||
return "", errors.New("Missing key: " + k)
|
||||
}
|
||||
|
||||
vS, ok := v.(string)
|
||||
if !ok {
|
||||
return "", errors.New("Malformatted key: " + k)
|
||||
}
|
||||
return vS, nil
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) FindOpen() ([]*model.Ticket, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) FindByTag(name, value string) ([]*model.Ticket, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) FindByTagName(name string) ([]*model.Ticket, error) {
|
||||
issues, _, err := j.api().Issue.Search("labels=comply", &jira.SearchOptions{MaxResults: 1000})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to fetch Jira issues")
|
||||
}
|
||||
return toTickets(issues), nil
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) LinkFor(t *model.Ticket) string {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) Create(ticket *model.Ticket, labels []string) error {
|
||||
i := jira.Issue{
|
||||
Fields: &jira.IssueFields{
|
||||
Type: jira.IssueType{
|
||||
Name: j.taskType,
|
||||
},
|
||||
Project: jira.Project{
|
||||
Key: j.project,
|
||||
},
|
||||
Summary: ticket.Name,
|
||||
Description: ticket.Body,
|
||||
Labels: labels,
|
||||
},
|
||||
}
|
||||
|
||||
_, _, err := j.api().Issue.Create(&i)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create ticket")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toTickets(issues []jira.Issue) []*model.Ticket {
|
||||
var tickets []*model.Ticket
|
||||
for _, i := range issues {
|
||||
tickets = append(tickets, toTicket(&i))
|
||||
}
|
||||
return tickets
|
||||
}
|
||||
|
||||
func toTicket(i *jira.Issue) *model.Ticket {
|
||||
t := &model.Ticket{Attributes: make(map[string]interface{})}
|
||||
t.ID = i.ID
|
||||
t.Name = i.Fields.Summary
|
||||
t.Body = i.Fields.Description
|
||||
createdAt := time.Time(i.Fields.Created)
|
||||
t.CreatedAt = &createdAt
|
||||
t.State = toState(i.Fields.Resolution)
|
||||
|
||||
for _, l := range i.Fields.Labels {
|
||||
t.SetBool(l)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func toState(status *jira.Resolution) model.TicketState {
|
||||
if status == nil {
|
||||
return model.Open
|
||||
}
|
||||
switch status.Name {
|
||||
case "Done":
|
||||
return model.Closed
|
||||
}
|
||||
return model.Open
|
||||
}
|
9
internal/jira/jira_test.go
Normal file
9
internal/jira/jira_test.go
Normal file
@ -0,0 +1,9 @@
|
||||
package jira
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJira(t *testing.T) {
|
||||
createOne()
|
||||
}
|
@ -2,7 +2,7 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Policy struct {
|
||||
type Document struct {
|
||||
Name string `yaml:"name"`
|
||||
Acronym string `yaml:"acronym"`
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
@ -91,8 +94,8 @@ func ReadStandards() ([]*Standard, error) {
|
||||
}
|
||||
|
||||
// ReadNarratives loads narrative descriptions from the filesystem.
|
||||
func ReadNarratives() ([]*Narrative, error) {
|
||||
var narratives []*Narrative
|
||||
func ReadNarratives() ([]*Document, error) {
|
||||
var narratives []*Document
|
||||
|
||||
files, err := path.Narratives()
|
||||
if err != nil {
|
||||
@ -100,8 +103,11 @@ func ReadNarratives() ([]*Narrative, error) {
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
n := &Narrative{}
|
||||
mdmd := loadMDMD(f.FullPath)
|
||||
n := &Document{}
|
||||
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() ([]*Narrative, 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)
|
||||
@ -141,8 +151,8 @@ func ReadProcedures() ([]*Procedure, error) {
|
||||
}
|
||||
|
||||
// ReadPolicies loads policy documents from the filesystem.
|
||||
func ReadPolicies() ([]*Policy, error) {
|
||||
var policies []*Policy
|
||||
func ReadPolicies() ([]*Document, error) {
|
||||
var policies []*Document
|
||||
|
||||
files, err := path.Policies()
|
||||
if err != nil {
|
||||
@ -150,8 +160,11 @@ func ReadPolicies() ([]*Policy, error) {
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
p := &Policy{}
|
||||
mdmd := loadMDMD(f.FullPath)
|
||||
p := &Document{}
|
||||
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,18 +184,20 @@ 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)
|
||||
}
|
||||
|
||||
content := string(bytes)
|
||||
components := strings.Split(content, "---")
|
||||
if len(components) == 1 {
|
||||
panic(fmt.Sprintf("Malformed metadata markdown in %s, must be of the form: YAML\\n---\\nmarkdown content", path))
|
||||
if components[0] == "" && (len(components) > 1) {
|
||||
components = components[1:]
|
||||
}
|
||||
yaml := components[0]
|
||||
if len(components) == 1 {
|
||||
return nil, errors.New(fmt.Sprintf("Malformed metadata markdown in %s, must be of the form: YAML\\n---\\nmarkdown content", path))
|
||||
}
|
||||
item := components[0]
|
||||
body := strings.Join(components[1:], "---")
|
||||
return metadataMarkdown{yaml, body}
|
||||
return &metadataMarkdown{item, body}, nil
|
||||
}
|
||||
|
238
internal/model/fs_test.go
Normal file
238
internal/model/fs_test.go
Normal file
@ -0,0 +1,238 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/strongdm/comply/internal/path"
|
||||
"github.com/strongdm/comply/internal/util"
|
||||
)
|
||||
|
||||
type ReadFiles struct{}
|
||||
|
||||
func beforeEach() {
|
||||
util.MockConfig()
|
||||
}
|
||||
|
||||
func TestReadFiles(t *testing.T) {
|
||||
util.ExecuteTests(t, reflect.TypeOf(ReadFiles{}), beforeEach, nil)
|
||||
}
|
||||
|
||||
// TestReadNarratives calls model.ReadNarratives checking for a valid return value.
|
||||
func (tg ReadFiles) TestReadNarratives(t *testing.T) {
|
||||
filePath := fmt.Sprintf("%s/narratives/control.md", util.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 (tg ReadFiles) TestReadNarrativesWhenThereAreNoNarratives(t *testing.T) {
|
||||
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 (tg ReadFiles) TestReadNarrativesFailsWhenInvalidNarrative(t *testing.T) {
|
||||
path.Narratives = func() ([]path.File, error) {
|
||||
filePath := fmt.Sprintf("%s/../fixtures/narratives/invalid-control.md", util.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 (tg ReadFiles) TestReadProcedures(t *testing.T) {
|
||||
filePath := fmt.Sprintf("%s/procedures/workstation.md", util.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 (tg ReadFiles) TestReadProceduresWhenThereAreNoProcedures(t *testing.T) {
|
||||
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 (tg ReadFiles) TestReadProceduresFailsWhenInvalidProcedure(t *testing.T) {
|
||||
path.Procedures = func() ([]path.File, error) {
|
||||
filePath := fmt.Sprintf("%s/../fixtures/procedures/invalid-workstation.md", util.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 (tg ReadFiles) TestReadPolicies(t *testing.T) {
|
||||
filePath := fmt.Sprintf("%s/policies/access.md", util.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 (tg ReadFiles) TestReadPoliciesWhenThereAreNoPolicies(t *testing.T) {
|
||||
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 (tg ReadFiles) TestReadPoliciesFailsWhenInvalidPolicy(t *testing.T) {
|
||||
path.Policies = func() ([]path.File, error) {
|
||||
filePath := fmt.Sprintf("%s/../fixtures/policies/invalid-access.md", util.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 (tg ReadFiles) TestReadStandards(t *testing.T) {
|
||||
filePath := fmt.Sprintf("%s/standards/TSC-2017.yml", util.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 (tg ReadFiles) TestReadStandardsWhenThereAreNoStandards(t *testing.T) {
|
||||
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 (tg ReadFiles) TestReadStandardsFailsWhenInvalidStandard(t *testing.T) {
|
||||
path.Standards = func() ([]path.File, error) {
|
||||
filePath := fmt.Sprintf("%s/../fixtures/standards/invalid-standard.yml", util.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)
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@ package model
|
||||
|
||||
type Data struct {
|
||||
Standards []*Standard
|
||||
Narratives []*Narrative
|
||||
Policies []*Policy
|
||||
Narratives []*Document
|
||||
Policies []*Document
|
||||
Procedures []*Procedure
|
||||
Tickets []*Ticket
|
||||
Audits []*Audit
|
||||
|
@ -9,36 +9,32 @@ 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",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
m, _ := json.Marshal(d)
|
||||
|
||||
encoded := string(m)
|
||||
|
||||
if !strings.Contains(encoded, "t1") ||
|
||||
!strings.Contains(encoded, "a1") ||
|
||||
!strings.Contains(encoded, "pro1") ||
|
||||
!strings.Contains(encoded, "pol1") {
|
||||
t.Error("identifier not found in marshalled string")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Narrative struct {
|
||||
Name string `yaml:"name"`
|
||||
Acronym string `yaml:"acronym"`
|
||||
|
||||
Revisions []Revision `yaml:"majorRevisions"`
|
||||
Satisfies Satisfaction `yaml:"satisfies"`
|
||||
FullPath string
|
||||
OutputFilename string
|
||||
ModifiedAt time.Time
|
||||
Body string
|
||||
}
|
@ -16,12 +16,23 @@ var tsConfigureOnce sync.Once
|
||||
type TicketSystem string
|
||||
|
||||
const (
|
||||
// JIRA from Atlassian.
|
||||
JIRA = TicketSystem("jira")
|
||||
// Github from Github.
|
||||
Github = TicketSystem("github")
|
||||
// Jira from Atlassian.
|
||||
Jira = TicketSystem(config.Jira)
|
||||
// GitHub from GitHub.
|
||||
GitHub = TicketSystem(config.GitHub)
|
||||
// GitLab from GitLab.
|
||||
GitLab = TicketSystem(config.GitLab)
|
||||
// NoTickets indicates no ticketing system integration.
|
||||
NoTickets = TicketSystem(config.NoTickets)
|
||||
)
|
||||
|
||||
type TicketLinks struct {
|
||||
ProcedureOpen string
|
||||
ProcedureAll string
|
||||
AuditOpen string
|
||||
AuditAll string
|
||||
}
|
||||
|
||||
// TicketPlugin models support for ticketing systems.
|
||||
type TicketPlugin interface {
|
||||
Get(ID string) (*Ticket, error)
|
||||
@ -31,6 +42,9 @@ type TicketPlugin interface {
|
||||
Create(ticket *Ticket, labels []string) error
|
||||
Configure(map[string]interface{}) error
|
||||
Prompts() map[string]string
|
||||
Links() TicketLinks
|
||||
LinkFor(ticket *Ticket) string
|
||||
Configured() bool
|
||||
}
|
||||
|
||||
// GetPlugin loads the ticketing database.
|
||||
@ -38,6 +52,10 @@ func GetPlugin(ts TicketSystem) TicketPlugin {
|
||||
tsPluginsMu.Lock()
|
||||
defer tsPluginsMu.Unlock()
|
||||
|
||||
if ts == NoTickets {
|
||||
return &noopTicketSystem{}
|
||||
}
|
||||
|
||||
tp, ok := tsPlugins[ts]
|
||||
if !ok {
|
||||
panic("Unknown ticket system: " + ts)
|
||||
@ -46,30 +64,34 @@ func GetPlugin(ts TicketSystem) TicketPlugin {
|
||||
if config.Exists() {
|
||||
tsConfigureOnce.Do(func() {
|
||||
ticketsMap := config.Config().Tickets
|
||||
hasTickets := true
|
||||
|
||||
cfg, ok := ticketsMap[string(ts)]
|
||||
if !ok {
|
||||
spew.Dump(cfg)
|
||||
panic(fmt.Sprintf("Missing configuration for plugin system; add `%s` block to project YAML", string(ts)))
|
||||
hasTickets = false
|
||||
}
|
||||
|
||||
cfgTyped, ok := cfg.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
spew.Dump(cfg)
|
||||
panic(fmt.Sprintf("malformatted ticket configuration block `%s` in project YAML", string(ts)))
|
||||
}
|
||||
|
||||
cfgStringed := make(map[string]interface{})
|
||||
for k, v := range cfgTyped {
|
||||
kS, ok := k.(string)
|
||||
if hasTickets {
|
||||
cfgTyped, ok := cfg.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
spew.Dump(cfgStringed)
|
||||
panic(fmt.Sprintf("malformatted key in configuration block `%s` in project YAML", string(ts)))
|
||||
spew.Dump(cfg)
|
||||
panic(fmt.Sprintf("malformatted ticket configuration block `%s` in project YAML", string(ts)))
|
||||
}
|
||||
cfgStringed[kS] = v
|
||||
}
|
||||
|
||||
tp.Configure(cfgStringed)
|
||||
cfgStringed := make(map[string]interface{})
|
||||
for k, v := range cfgTyped {
|
||||
kS, ok := k.(string)
|
||||
if !ok {
|
||||
spew.Dump(cfgStringed)
|
||||
panic(fmt.Sprintf("malformatted key in configuration block `%s` in project YAML", string(ts)))
|
||||
}
|
||||
cfgStringed[kS] = v
|
||||
}
|
||||
err := tp.Configure(cfgStringed)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Configuration error `%s` in project YAML", err))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -87,3 +109,36 @@ func Register(ts TicketSystem, plugin TicketPlugin) {
|
||||
|
||||
tsPlugins[ts] = plugin
|
||||
}
|
||||
|
||||
type noopTicketSystem struct{}
|
||||
|
||||
func (*noopTicketSystem) Get(ID string) (*Ticket, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (*noopTicketSystem) FindOpen() ([]*Ticket, error) {
|
||||
return []*Ticket{}, nil
|
||||
}
|
||||
func (*noopTicketSystem) FindByTag(name, value string) ([]*Ticket, error) {
|
||||
return []*Ticket{}, nil
|
||||
}
|
||||
func (*noopTicketSystem) FindByTagName(name string) ([]*Ticket, error) {
|
||||
return []*Ticket{}, nil
|
||||
}
|
||||
func (*noopTicketSystem) Create(ticket *Ticket, labels []string) error {
|
||||
return nil
|
||||
}
|
||||
func (*noopTicketSystem) Configure(map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
func (*noopTicketSystem) Prompts() map[string]string {
|
||||
return make(map[string]string)
|
||||
}
|
||||
func (*noopTicketSystem) Links() TicketLinks {
|
||||
return TicketLinks{}
|
||||
}
|
||||
func (*noopTicketSystem) LinkFor(ticket *Ticket) string {
|
||||
return ""
|
||||
}
|
||||
func (*noopTicketSystem) Configured() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,9 @@ package github
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
@ -31,7 +33,7 @@ func (g *githubPlugin) Prompts() map[string]string {
|
||||
|
||||
// Register causes the Github plugin to register itself
|
||||
func Register() {
|
||||
model.Register(model.Github, &githubPlugin{})
|
||||
model.Register(model.GitHub, &githubPlugin{})
|
||||
}
|
||||
|
||||
type githubPlugin struct {
|
||||
@ -63,6 +65,19 @@ func (g *githubPlugin) Get(ID string) (*model.Ticket, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (g *githubPlugin) Configured() bool {
|
||||
return g.username != "" && g.reponame != "" && g.token != ""
|
||||
}
|
||||
|
||||
func (g *githubPlugin) Links() model.TicketLinks {
|
||||
links := model.TicketLinks{}
|
||||
links.AuditAll = fmt.Sprintf("https://github.com/%s/%s/issues?q=is%%3Aissue+is%%3Aopen+label%%3Acomply+label%%3Aaudit", g.username, g.reponame)
|
||||
links.AuditOpen = fmt.Sprintf("https://github.com/%s/%s/issues?q=is%%3Aissue+is%%3Aopen+label%%3Acomply+label%%3Aaudit", g.username, g.reponame)
|
||||
links.ProcedureAll = fmt.Sprintf("https://github.com/%s/%s/issues?q=is%%3Aissue+label%%3Acomply+label%%3Acomply-procedure", g.username, g.reponame)
|
||||
links.ProcedureOpen = fmt.Sprintf("https://github.com/%s/%s/issues?q=is%%3Aissue+is%%3Aopen+label%%3Acomply+label%%3Acomply-procedure", g.username, g.reponame)
|
||||
return links
|
||||
}
|
||||
|
||||
func (g *githubPlugin) Configure(cfg map[string]interface{}) error {
|
||||
var err error
|
||||
|
||||
@ -82,7 +97,10 @@ func (g *githubPlugin) Configure(cfg map[string]interface{}) error {
|
||||
func getCfg(cfg map[string]interface{}, k string) (string, error) {
|
||||
v, ok := cfg[k]
|
||||
if !ok {
|
||||
return "", errors.New("Missing key: " + k)
|
||||
v = os.Getenv(fmt.Sprintf("GITHUB_%s", strings.ToUpper(k)))
|
||||
if v == "" {
|
||||
return "", errors.New("Missing key: " + k)
|
||||
}
|
||||
}
|
||||
|
||||
vS, ok := v.(string)
|
||||
@ -122,12 +140,8 @@ func (g *githubPlugin) FindByTagName(name string) ([]*model.Ticket, error) {
|
||||
}
|
||||
|
||||
func (g *githubPlugin) LinkFor(t *model.Ticket) string {
|
||||
return fmt.Sprintf("https://github.com/strongdm/comply/issues/%s", t.ID)
|
||||
}
|
||||
|
||||
func (g *githubPlugin) Links() (string, string) {
|
||||
return fmt.Sprintf("https://github.com/strongdm/comply/issues?q=is%3Aissue+is%3Aclosed+label%3Acomply", g.username, g.reponame),
|
||||
fmt.Sprintf("https://github.com/%s/%s/issues?q=is%3Aissue+is%3Aopen+label%3Acomply", g.username, g.reponame)
|
||||
// return fmt.Sprintf("https://github.com/strongdm/comply/issues/%s", t.ID)
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (g *githubPlugin) Create(ticket *model.Ticket, labels []string) error {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
)
|
||||
@ -18,9 +19,9 @@ type stats struct {
|
||||
ControlsTotal int
|
||||
ControlsSatisfied int
|
||||
|
||||
ProcessTotal int
|
||||
ProcessOpen int
|
||||
ProcessOldestDays int
|
||||
ProcedureTotal int
|
||||
ProcedureOpen int
|
||||
ProcedureOldestDays int
|
||||
|
||||
AuditOpen int
|
||||
AuditClosed int
|
||||
@ -32,12 +33,13 @@ type renderData struct {
|
||||
Name string
|
||||
Project *project
|
||||
Stats *stats
|
||||
Narratives []*model.Narrative
|
||||
Policies []*model.Policy
|
||||
Narratives []*model.Document
|
||||
Policies []*model.Document
|
||||
Procedures []*model.Procedure
|
||||
Standards []*model.Standard
|
||||
Tickets []*model.Ticket
|
||||
Controls []*control
|
||||
Links *model.TicketLinks
|
||||
}
|
||||
|
||||
type control struct {
|
||||
@ -87,9 +89,22 @@ func load() (*model.Data, *renderData, error) {
|
||||
rd.Procedures = modelData.Procedures
|
||||
rd.Standards = modelData.Standards
|
||||
rd.Tickets = modelData.Tickets
|
||||
rd.Links = &model.TicketLinks{}
|
||||
rd.Project = project
|
||||
rd.Name = project.OrganizationName
|
||||
rd.Controls = controls
|
||||
|
||||
ts, err := config.Config().TicketSystem()
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "error in ticket system configuration")
|
||||
}
|
||||
|
||||
tp := model.GetPlugin(model.TicketSystem(ts))
|
||||
if tp.Configured() {
|
||||
links := tp.Links()
|
||||
rd.Links = &links
|
||||
}
|
||||
|
||||
return modelData, rd, nil
|
||||
}
|
||||
|
||||
@ -123,12 +138,12 @@ func addStats(modelData *model.Data, renderData *renderData) {
|
||||
}
|
||||
|
||||
if t.State == model.Open {
|
||||
if t.Bool("process") {
|
||||
stats.ProcessOpen++
|
||||
if t.Bool("comply-procedure") {
|
||||
stats.ProcedureOpen++
|
||||
if t.CreatedAt != nil {
|
||||
age := int(time.Since(*t.CreatedAt).Hours() / float64(24))
|
||||
if stats.ProcessOldestDays < age {
|
||||
stats.ProcessOldestDays = age
|
||||
if stats.ProcedureOldestDays < age {
|
||||
stats.ProcedureOldestDays = age
|
||||
}
|
||||
}
|
||||
}
|
||||
|
170
internal/render/document.go
Normal file
170
internal/render/document.go
Normal file
@ -0,0 +1,170 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"os/exec"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
)
|
||||
|
||||
// TODO: refactor and eliminate duplication among narrative, policy renderers
|
||||
func renderToFilesystem(wg *sync.WaitGroup, errOutputCh chan error, data *renderData, doc *model.Document, live bool) {
|
||||
// only files that have been touched
|
||||
if !isNewer(doc.FullPath, doc.ModifiedAt) {
|
||||
return
|
||||
}
|
||||
recordModified(doc.FullPath, doc.ModifiedAt)
|
||||
|
||||
wg.Add(1)
|
||||
go func(p *model.Document) {
|
||||
defer wg.Done()
|
||||
|
||||
outputFilename := p.OutputFilename
|
||||
// save preprocessed markdown
|
||||
err := preprocessDoc(data, p, filepath.Join(".", "output", outputFilename+".md"))
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to preprocess")
|
||||
return
|
||||
}
|
||||
|
||||
pandoc(outputFilename, errOutputCh)
|
||||
|
||||
// remove preprocessed markdown
|
||||
err = os.Remove(filepath.Join(".", "output", outputFilename+".md"))
|
||||
if err != nil {
|
||||
errOutputCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
rel, err := filepath.Rel(config.ProjectRoot(), p.FullPath)
|
||||
if err != nil {
|
||||
rel = p.FullPath
|
||||
}
|
||||
fmt.Printf("%s -> %s\n", rel, filepath.Join("output", p.OutputFilename))
|
||||
}(doc)
|
||||
}
|
||||
|
||||
func getGitApprovalInfo(pol *model.Document) (string, error) {
|
||||
cfg := config.Config()
|
||||
|
||||
// if no approved branch specified in config.yaml, then nothing gets added to the document
|
||||
if cfg.ApprovedBranch == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Decide whether we are on the git branch that contains the approved policies
|
||||
gitBranchArgs := []string{"rev-parse", "--abbrev-ref", "HEAD"}
|
||||
gitBranchCmd := exec.Command("git", gitBranchArgs...)
|
||||
gitBranchInfo, err := gitBranchCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Println(string(gitBranchInfo))
|
||||
return "", errors.Wrap(err, "error looking up git branch")
|
||||
}
|
||||
|
||||
// if on a different branch than the approved branch, then nothing gets added to the document
|
||||
if strings.Compare(strings.TrimSpace(fmt.Sprintf("%s", gitBranchInfo)), cfg.ApprovedBranch) != 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Grab information related to commit, so that we can put approval information in the document
|
||||
gitArgs := []string{"log", "-n", "1", "--pretty=format:Last edit made by %an (%aE) on %aD.\n\nApproved by %cn (%cE) on %cD in commit %H.", "--", pol.FullPath}
|
||||
cmd := exec.Command("git", gitArgs...)
|
||||
gitApprovalInfo, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Println(string(gitApprovalInfo))
|
||||
return "", errors.Wrap(err, "error looking up git committer and author data")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s\n%s", "# Authorship and Approval", gitApprovalInfo), nil
|
||||
}
|
||||
|
||||
func preprocessDoc(data *renderData, pol *model.Document, fullPath string) error {
|
||||
cfg := config.Config()
|
||||
|
||||
var w bytes.Buffer
|
||||
bodyTemplate, err := template.New("body").Parse(pol.Body)
|
||||
if err != nil {
|
||||
w.WriteString(fmt.Sprintf("# Error processing template:\n\n%s\n", err.Error()))
|
||||
} else {
|
||||
bodyTemplate.Execute(&w, data)
|
||||
}
|
||||
body := w.String()
|
||||
|
||||
revisionTable := ""
|
||||
satisfiesTable := ""
|
||||
|
||||
// ||Date|Comment|
|
||||
// |---+------|
|
||||
// | 4 Jan 2018 | Initial Version |
|
||||
// Table: Document history
|
||||
|
||||
if len(pol.Satisfies) > 0 {
|
||||
rows := ""
|
||||
for standard, keys := range pol.Satisfies {
|
||||
rows += fmt.Sprintf("| %s | %s |\n", standard, strings.Join(keys, ", "))
|
||||
}
|
||||
satisfiesTable = fmt.Sprintf("|Standard|Controls Satisfied|\n|-------+--------------------------------------------|\n%s\nTable: Control satisfaction\n", rows)
|
||||
}
|
||||
|
||||
if len(pol.Revisions) > 0 {
|
||||
rows := ""
|
||||
for _, rev := range pol.Revisions {
|
||||
rows += fmt.Sprintf("| %s | %s |\n", rev.Date, rev.Comment)
|
||||
}
|
||||
revisionTable = fmt.Sprintf("|Date|Comment|\n|---+--------------------------------------------|\n%s\nTable: Document history\n", rows)
|
||||
}
|
||||
|
||||
gitApprovalInfo, err := getGitApprovalInfo(pol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
doc := fmt.Sprintf(`%% %s
|
||||
%% %s
|
||||
%% %s
|
||||
|
||||
---
|
||||
header-includes: |
|
||||
\usepackage{fancyhdr}
|
||||
\pagestyle{fancy}
|
||||
\fancyhead{}
|
||||
\fancyhead[RO,RE]{%s}
|
||||
\fancyfoot[LO,LE]{%s confidential %d}
|
||||
---
|
||||
|
||||
%s
|
||||
|
||||
%s
|
||||
|
||||
\newpage
|
||||
%s
|
||||
|
||||
%s`,
|
||||
pol.Name,
|
||||
cfg.Name,
|
||||
fmt.Sprintf("%s %d", pol.ModifiedAt.Month().String(), pol.ModifiedAt.Year()),
|
||||
pol.Name,
|
||||
cfg.Name,
|
||||
time.Now().Year(),
|
||||
satisfiesTable,
|
||||
revisionTable,
|
||||
body,
|
||||
gitApprovalInfo,
|
||||
)
|
||||
err = ioutil.WriteFile(fullPath, []byte(doc), os.FileMode(0644))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to write preprocessed policy to disk")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -9,12 +9,16 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/skratchdot/open-golang/open"
|
||||
"github.com/yosssi/ace"
|
||||
)
|
||||
|
||||
const websocketReloader = `<script>
|
||||
(function(){
|
||||
var ws = new WebSocket("ws://localhost:5122/ws")
|
||||
var ws = new WebSocket("ws://localhost:%d/ws")
|
||||
if (location.host != "") {
|
||||
ws = new WebSocket("ws://"+location.host+"/ws")
|
||||
}
|
||||
var connected = false
|
||||
ws.onopen = function(e) {
|
||||
connected = true
|
||||
@ -22,13 +26,15 @@ const websocketReloader = `<script>
|
||||
ws.onclose = function(e) {
|
||||
// reload!
|
||||
if (connected) {
|
||||
window.location=window.location
|
||||
window.location.reload(true)
|
||||
}
|
||||
}
|
||||
})()
|
||||
</script>`
|
||||
|
||||
func html(output string, live bool, errCh chan error, wg *sync.WaitGroup) {
|
||||
opened := false
|
||||
|
||||
for {
|
||||
files, err := ioutil.ReadDir(filepath.Join(".", "templates"))
|
||||
if err != nil {
|
||||
@ -48,12 +54,16 @@ func html(output string, live bool, errCh chan error, wg *sync.WaitGroup) {
|
||||
}
|
||||
|
||||
basename := strings.Replace(fileInfo.Name(), ".ace", "", -1)
|
||||
w, err := os.Create(filepath.Join(output, fmt.Sprintf("%s.html", basename)))
|
||||
outputFilename := filepath.Join(output, fmt.Sprintf("%s.html", basename))
|
||||
|
||||
w, err := os.Create(outputFilename)
|
||||
if err != nil {
|
||||
errCh <- errors.Wrap(err, "unable to create HTML file")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%s -> %s\n", filepath.Join("templates", fileInfo.Name()), outputFilename)
|
||||
|
||||
tpl, err := ace.Load("", filepath.Join("templates", basename), aceOpts)
|
||||
if err != nil {
|
||||
w.Write([]byte("<htmL><body>template error</body></html>"))
|
||||
@ -67,14 +77,21 @@ func html(output string, live bool, errCh chan error, wg *sync.WaitGroup) {
|
||||
}
|
||||
|
||||
if live {
|
||||
w.Write([]byte(websocketReloader))
|
||||
w.Write([]byte(fmt.Sprintf(websocketReloader, ServePort)))
|
||||
}
|
||||
w.Close()
|
||||
}
|
||||
if !live {
|
||||
|
||||
if live {
|
||||
if !opened {
|
||||
opened = true
|
||||
open.Run(fmt.Sprintf("http://127.0.0.1:%d/", ServePort))
|
||||
}
|
||||
} else {
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
<-subscribe()
|
||||
}
|
||||
}
|
||||
|
@ -1,185 +0,0 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
)
|
||||
|
||||
// TODO: refactor and eliminate duplication among narrative, policy renderers
|
||||
func renderNarrativeToDisk(wg *sync.WaitGroup, errOutputCh chan error, data *renderData, narrative *model.Narrative, live bool) {
|
||||
// only files that have been touched
|
||||
if !isNewer(narrative.FullPath, narrative.ModifiedAt) {
|
||||
return
|
||||
}
|
||||
recordModified(narrative.FullPath, narrative.ModifiedAt)
|
||||
|
||||
ctx := context.Background()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to read Docker environment")
|
||||
return
|
||||
}
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to get workding directory")
|
||||
return
|
||||
}
|
||||
|
||||
hc := &container.HostConfig{
|
||||
Binds: []string{pwd + ":/source"},
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(p *model.Narrative) {
|
||||
defer wg.Done()
|
||||
|
||||
if live {
|
||||
rel, err := filepath.Rel(config.ProjectRoot(), p.FullPath)
|
||||
if err != nil {
|
||||
rel = p.FullPath
|
||||
}
|
||||
fmt.Printf("%s -> %s\n", rel, filepath.Join("output", p.OutputFilename))
|
||||
}
|
||||
|
||||
outputFilename := p.OutputFilename
|
||||
// save preprocessed markdown
|
||||
err = preprocessNarrative(data, p, filepath.Join(".", "output", outputFilename+".md"))
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to preprocess")
|
||||
return
|
||||
}
|
||||
|
||||
cmd := []string{"--smart", "--toc", "-N", "--template=/source/templates/default.latex", "-o",
|
||||
fmt.Sprintf("/source/output/%s", outputFilename),
|
||||
fmt.Sprintf("/source/output/%s.md", outputFilename)}
|
||||
|
||||
resp, err := cli.ContainerCreate(ctx, &container.Config{
|
||||
Image: "strongdm/pandoc",
|
||||
Cmd: cmd},
|
||||
hc, nil, "")
|
||||
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to create Docker container")
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
timeout := 2 * time.Second
|
||||
cli.ContainerStop(ctx, resp.ID, &timeout)
|
||||
err := cli.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to remove container")
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to start Docker container")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = cli.ContainerWait(ctx, resp.ID)
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "error awaiting Docker container")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = cli.ContainerLogs(ctx, resp.ID, types.ContainerLogsOptions{ShowStdout: true})
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "error reading Docker container logs")
|
||||
return
|
||||
}
|
||||
|
||||
// remove preprocessed markdown
|
||||
err = os.Remove(filepath.Join(".", "output", outputFilename+".md"))
|
||||
if err != nil {
|
||||
errOutputCh <- err
|
||||
return
|
||||
}
|
||||
}(narrative)
|
||||
}
|
||||
|
||||
func preprocessNarrative(data *renderData, pol *model.Narrative, fullPath string) error {
|
||||
cfg := config.Config()
|
||||
|
||||
var w bytes.Buffer
|
||||
bodyTemplate, err := template.New("body").Parse(pol.Body)
|
||||
if err != nil {
|
||||
w.WriteString(fmt.Sprintf("# Error processing template:\n\n%s\n", err.Error()))
|
||||
} else {
|
||||
bodyTemplate.Execute(&w, data)
|
||||
}
|
||||
body := w.String()
|
||||
|
||||
revisionTable := ""
|
||||
satisfiesTable := ""
|
||||
|
||||
// ||Date|Comment|
|
||||
// |---+------|
|
||||
// | 4 Jan 2018 | Initial Version |
|
||||
// Table: Document history
|
||||
|
||||
if len(pol.Satisfies) > 0 {
|
||||
rows := ""
|
||||
for standard, keys := range pol.Satisfies {
|
||||
rows += fmt.Sprintf("| %s | %s |\n", standard, strings.Join(keys, ", "))
|
||||
}
|
||||
satisfiesTable = fmt.Sprintf("|Standard|Controls Satisfied|\n|-------+--------------------------------------------|\n%s\nTable: Control satisfaction\n", rows)
|
||||
}
|
||||
|
||||
if len(pol.Revisions) > 0 {
|
||||
rows := ""
|
||||
for _, rev := range pol.Revisions {
|
||||
rows += fmt.Sprintf("| %s | %s |\n", rev.Date, rev.Comment)
|
||||
}
|
||||
revisionTable = fmt.Sprintf("|Date|Comment|\n|---+--------------------------------------------|\n%s\nTable: Document history\n", rows)
|
||||
}
|
||||
|
||||
doc := fmt.Sprintf(`%% %s
|
||||
%% %s
|
||||
%% %s
|
||||
|
||||
---
|
||||
header-includes: yes
|
||||
head-content: "%s"
|
||||
foot-content: "%s confidential %d"
|
||||
---
|
||||
|
||||
%s
|
||||
|
||||
%s
|
||||
|
||||
\newpage
|
||||
%s`,
|
||||
pol.Name,
|
||||
cfg.Name,
|
||||
fmt.Sprintf("%s %d", pol.ModifiedAt.Month().String(), pol.ModifiedAt.Year()),
|
||||
pol.Name,
|
||||
cfg.Name,
|
||||
time.Now().Year(),
|
||||
satisfiesTable,
|
||||
revisionTable,
|
||||
body,
|
||||
)
|
||||
err = ioutil.WriteFile(fullPath, []byte(doc), os.FileMode(0644))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to write preprocessed narrative to disk")
|
||||
}
|
||||
return nil
|
||||
}
|
105
internal/render/pandoc.go
Normal file
105
internal/render/pandoc.go
Normal file
@ -0,0 +1,105 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
)
|
||||
|
||||
var pandocArgs = []string{"-f", "markdown+smart", "--toc", "-N", "--template", "templates/default.latex", "-o"}
|
||||
|
||||
func pandoc(outputFilename string, errOutputCh chan error) {
|
||||
if config.WhichPandoc() == config.UsePandoc {
|
||||
pandocPandoc(outputFilename, errOutputCh)
|
||||
} else {
|
||||
dockerPandoc(outputFilename, errOutputCh)
|
||||
}
|
||||
}
|
||||
|
||||
func dockerPandoc(outputFilename string, errOutputCh chan error) {
|
||||
pandocCmd := append(pandocArgs, fmt.Sprintf("/source/output/%s", outputFilename), fmt.Sprintf("/source/output/%s.md", outputFilename))
|
||||
ctx := context.Background()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to read Docker environment")
|
||||
return
|
||||
}
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to get workding directory")
|
||||
return
|
||||
}
|
||||
|
||||
hc := &container.HostConfig{
|
||||
Binds: []string{pwd + ":/source"},
|
||||
}
|
||||
|
||||
resp, err := cli.ContainerCreate(ctx, &container.Config{
|
||||
Image: "strongdm/pandoc:edge",
|
||||
Cmd: pandocCmd},
|
||||
hc, nil, nil, "")
|
||||
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to create Docker container")
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
timeout := 2 * time.Second
|
||||
cli.ContainerStop(ctx, resp.ID, &timeout)
|
||||
err := cli.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to remove container")
|
||||
return
|
||||
}
|
||||
errOutputCh <- nil
|
||||
}()
|
||||
|
||||
err = cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to start Docker container")
|
||||
return
|
||||
}
|
||||
|
||||
chanResult, chanErr := cli.ContainerWait(ctx, resp.ID, "not-running")
|
||||
resultValue := <-chanResult
|
||||
|
||||
if resultValue.StatusCode != 0 {
|
||||
err = <-chanErr
|
||||
errOutputCh <- errors.Wrap(err, "error awaiting Docker container")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = cli.ContainerLogs(ctx, resp.ID, types.ContainerLogsOptions{ShowStdout: true})
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "error reading Docker container logs")
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = os.Stat(fmt.Sprintf("output/%s", outputFilename)); err != nil && os.IsNotExist(err) {
|
||||
errOutputCh <- errors.Wrap(err, "output not generated; verify your Docker image is up to date")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 🐼
|
||||
func pandocPandoc(outputFilename string, errOutputCh chan error) error {
|
||||
cmd := exec.Command("pandoc", append(pandocArgs, fmt.Sprintf("output/%s", outputFilename), fmt.Sprintf("output/%s.md", outputFilename))...)
|
||||
outputRaw, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Println(string(outputRaw))
|
||||
errOutputCh <- errors.Wrap(err, "error calling pandoc")
|
||||
} else {
|
||||
errOutputCh <- nil
|
||||
}
|
||||
return nil
|
||||
}
|
@ -25,7 +25,13 @@ func pdf(output string, live bool, errCh chan error, wg *sync.WaitGroup) {
|
||||
return
|
||||
}
|
||||
for _, policy := range policies {
|
||||
renderPolicyToDisk(&pdfWG, errOutputCh, data, policy, live)
|
||||
renderToFilesystem(&pdfWG, errOutputCh, data, policy, live)
|
||||
err = <-errOutputCh
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
narratives, err := model.ReadNarratives()
|
||||
@ -35,7 +41,13 @@ func pdf(output string, live bool, errCh chan error, wg *sync.WaitGroup) {
|
||||
}
|
||||
|
||||
for _, narrative := range narratives {
|
||||
renderNarrativeToDisk(&pdfWG, errOutputCh, data, narrative, live)
|
||||
renderToFilesystem(&pdfWG, errOutputCh, data, narrative, live)
|
||||
err = <-errOutputCh
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
pdfWG.Wait()
|
||||
|
@ -1,183 +0,0 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
)
|
||||
|
||||
// TODO: refactor and eliminate duplication among narrative, policy renderers
|
||||
func renderPolicyToDisk(wg *sync.WaitGroup, errOutputCh chan error, data *renderData, policy *model.Policy, live bool) {
|
||||
// only files that have been touched
|
||||
if !isNewer(policy.FullPath, policy.ModifiedAt) {
|
||||
return
|
||||
}
|
||||
recordModified(policy.FullPath, policy.ModifiedAt)
|
||||
|
||||
ctx := context.Background()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to read Docker environment")
|
||||
return
|
||||
}
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to get workding directory")
|
||||
return
|
||||
}
|
||||
|
||||
hc := &container.HostConfig{
|
||||
Binds: []string{pwd + ":/source"},
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(p *model.Policy) {
|
||||
defer wg.Done()
|
||||
|
||||
if live {
|
||||
rel, err := filepath.Rel(config.ProjectRoot(), p.FullPath)
|
||||
if err != nil {
|
||||
rel = p.FullPath
|
||||
}
|
||||
fmt.Printf("%s -> %s\n", rel, filepath.Join("output", p.OutputFilename))
|
||||
}
|
||||
|
||||
outputFilename := p.OutputFilename
|
||||
// save preprocessed markdown
|
||||
err = preprocessPolicy(data, p, filepath.Join(".", "output", outputFilename+".md"))
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to preprocess")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := cli.ContainerCreate(ctx, &container.Config{
|
||||
Image: "strongdm/pandoc",
|
||||
Cmd: []string{"--smart", "--toc", "-N", "--template=/source/templates/default.latex", "-o",
|
||||
fmt.Sprintf("/source/output/%s", outputFilename),
|
||||
fmt.Sprintf("/source/output/%s.md", outputFilename),
|
||||
},
|
||||
}, hc, nil, "")
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to create Docker container")
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
timeout := 2 * time.Second
|
||||
cli.ContainerStop(ctx, resp.ID, &timeout)
|
||||
err := cli.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to remove container")
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "unable to start Docker container")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = cli.ContainerWait(ctx, resp.ID)
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "error awaiting Docker container")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = cli.ContainerLogs(ctx, resp.ID, types.ContainerLogsOptions{ShowStdout: true})
|
||||
if err != nil {
|
||||
errOutputCh <- errors.Wrap(err, "error reading Docker container logs")
|
||||
return
|
||||
}
|
||||
|
||||
// remove preprocessed markdown
|
||||
err = os.Remove(filepath.Join(".", "output", outputFilename+".md"))
|
||||
if err != nil {
|
||||
errOutputCh <- err
|
||||
return
|
||||
}
|
||||
}(policy)
|
||||
}
|
||||
|
||||
func preprocessPolicy(data *renderData, pol *model.Policy, fullPath string) error {
|
||||
cfg := config.Config()
|
||||
|
||||
var w bytes.Buffer
|
||||
bodyTemplate, err := template.New("body").Parse(pol.Body)
|
||||
if err != nil {
|
||||
w.WriteString(fmt.Sprintf("# Error processing template:\n\n%s\n", err.Error()))
|
||||
} else {
|
||||
bodyTemplate.Execute(&w, data)
|
||||
}
|
||||
body := w.String()
|
||||
|
||||
revisionTable := ""
|
||||
satisfiesTable := ""
|
||||
|
||||
// ||Date|Comment|
|
||||
// |---+------|
|
||||
// | 4 Jan 2018 | Initial Version |
|
||||
// Table: Document history
|
||||
|
||||
if len(pol.Satisfies) > 0 {
|
||||
rows := ""
|
||||
for standard, keys := range pol.Satisfies {
|
||||
rows += fmt.Sprintf("| %s | %s |\n", standard, strings.Join(keys, ", "))
|
||||
}
|
||||
satisfiesTable = fmt.Sprintf("|Standard|Controls Satisfied|\n|-------+--------------------------------------------|\n%s\nTable: Control satisfaction\n", rows)
|
||||
}
|
||||
|
||||
if len(pol.Revisions) > 0 {
|
||||
rows := ""
|
||||
for _, rev := range pol.Revisions {
|
||||
rows += fmt.Sprintf("| %s | %s |\n", rev.Date, rev.Comment)
|
||||
}
|
||||
revisionTable = fmt.Sprintf("|Date|Comment|\n|---+--------------------------------------------|\n%s\nTable: Document history\n", rows)
|
||||
}
|
||||
|
||||
doc := fmt.Sprintf(`%% %s
|
||||
%% %s
|
||||
%% %s
|
||||
|
||||
---
|
||||
header-includes: yes
|
||||
head-content: "%s"
|
||||
foot-content: "%s confidential %d"
|
||||
---
|
||||
|
||||
%s
|
||||
|
||||
%s
|
||||
|
||||
\newpage
|
||||
%s`,
|
||||
pol.Name,
|
||||
cfg.Name,
|
||||
fmt.Sprintf("%s %d", pol.ModifiedAt.Month().String(), pol.ModifiedAt.Year()),
|
||||
pol.Name,
|
||||
cfg.Name,
|
||||
time.Now().Year(),
|
||||
satisfiesTable,
|
||||
revisionTable,
|
||||
body,
|
||||
)
|
||||
err = ioutil.WriteFile(fullPath, []byte(doc), os.FileMode(0644))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to write preprocessed policy to disk")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,17 +1,22 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/skratchdot/open-golang/open"
|
||||
"github.com/yosssi/ace"
|
||||
)
|
||||
|
||||
const BindAddress = "0.0.0.0"
|
||||
|
||||
var ServePort int
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
@ -88,6 +93,16 @@ func Build(output string, live bool) error {
|
||||
|
||||
if live {
|
||||
watch(errCh)
|
||||
|
||||
go func() {
|
||||
http.Handle("/", http.FileServer(http.Dir(filepath.Join(".", "output"))))
|
||||
err := http.ListenAndServe(fmt.Sprintf("%s:%d", BindAddress, ServePort), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
fmt.Printf("Serving content of output/ at http://%s:%d (ctrl-c to quit)\n", BindAddress, ServePort)
|
||||
}
|
||||
// PDF
|
||||
wg.Add(1)
|
||||
@ -103,10 +118,6 @@ func Build(output string, live bool) error {
|
||||
close(wgCh)
|
||||
}()
|
||||
|
||||
if live {
|
||||
open.Run("output/index.html")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-wgCh:
|
||||
// success
|
||||
|
@ -8,12 +8,14 @@ import (
|
||||
)
|
||||
|
||||
func watch(errCh chan error) {
|
||||
b, err := watcher.New(300 * time.Millisecond)
|
||||
// TODO: study about the poll duration
|
||||
b, err := watcher.New(300 * time.Millisecond, 0, false)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
b.Add("./templates/")
|
||||
b.Add("./narratives/")
|
||||
b.Add("./policies/")
|
||||
b.Add("./procedures/")
|
||||
|
||||
@ -24,7 +26,7 @@ func watch(errCh chan error) {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case e := <-b.Errors:
|
||||
case e := <-b.Errors():
|
||||
errCh <- e
|
||||
case <-b.Events:
|
||||
broadcast()
|
||||
@ -44,7 +46,6 @@ func watch(errCh chan error) {
|
||||
}
|
||||
|
||||
http.HandleFunc("/ws", serveWs)
|
||||
go http.ListenAndServe("127.0.0.1:5122", nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
1
internal/theme/.gitignore
vendored
1
internal/theme/.gitignore
vendored
@ -1 +0,0 @@
|
||||
themes_bindata.go
|
@ -1,13 +1,18 @@
|
||||
package theme
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func SaveTo(themeName, saveDir string) error {
|
||||
// SaveTo persists a compliance theme to a destination directory with optional
|
||||
// template value replacements.
|
||||
func SaveTo(themeName string, replace map[string]string, saveDir string) error {
|
||||
for _, name := range AssetNames() {
|
||||
prefix := themeName + "/"
|
||||
if strings.HasPrefix(name, prefix) {
|
||||
@ -17,7 +22,26 @@ func SaveTo(themeName, saveDir string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(saveDir, assetDir, assetFilename), MustAsset(name), os.FileMode(0644))
|
||||
|
||||
// special case for README.md and TODO.md: all other templates
|
||||
// are passed copied verbatim.
|
||||
if name == filepath.Join(themeName, "README.md") || name == filepath.Join(themeName, "TODO.md") {
|
||||
rootMdFile := string(MustAsset(name))
|
||||
|
||||
var w bytes.Buffer
|
||||
var rootMdFileTemplate *template.Template
|
||||
rootMdFileTemplate, err = template.New("rootMdFile").Parse(rootMdFile)
|
||||
if err != nil {
|
||||
w.WriteString(fmt.Sprintf("# Error processing template:\n\n%s\n", err.Error()))
|
||||
} else {
|
||||
rootMdFileTemplate.Execute(&w, replace)
|
||||
}
|
||||
body := w.String()
|
||||
err = ioutil.WriteFile(filepath.Join(saveDir, assetDir, assetFilename), []byte(body), os.FileMode(0644))
|
||||
} else {
|
||||
err = ioutil.WriteFile(filepath.Join(saveDir, assetDir, assetFilename), MustAsset(name), os.FileMode(0644))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
1489
internal/theme/themes_bindata.go
Normal file
1489
internal/theme/themes_bindata.go
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user