mirror of
https://github.com/strongdm/comply
synced 2025-12-15 19:00:50 +00:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5f7c08b73 | ||
|
|
b2276f9e54 | ||
|
|
f1b5bbeff9 | ||
|
|
b7acb1eecf | ||
|
|
da8a574e86 | ||
|
|
7468711b3b | ||
|
|
8baf787ed7 | ||
|
|
4c5c18964b | ||
|
|
c5a1bd804b | ||
|
|
c303b68201 | ||
|
|
87e8266f1b | ||
|
|
e8d6d536a8 | ||
|
|
ef7a4092a7 | ||
|
|
9bcc88eebc | ||
|
|
edd3c7dd44 | ||
|
|
25058359ea | ||
|
|
c4a0b7afff | ||
|
|
ef32942dad | ||
|
|
0c9dbd736b | ||
|
|
b98d179847 | ||
|
|
435ac086c0 | ||
|
|
0ddbb6cf52 | ||
|
|
3ebccc2811 | ||
|
|
b39bec8108 | ||
|
|
c699c64627 | ||
|
|
24ff9dd762 | ||
|
|
5c160d1ec5 | ||
|
|
f3088bfe28 | ||
|
|
aa57be25c9 | ||
|
|
2cef618abb | ||
|
|
e8a0ecd076 | ||
|
|
1a3e2a2bf7 | ||
|
|
7225741a46 | ||
|
|
7105d2d4ef | ||
|
|
e3fb66b0e4 | ||
|
|
1028521ea7 | ||
|
|
b2c2bf3558 | ||
|
|
d44af2e1cd | ||
|
|
e2281b5fe3 | ||
|
|
d43aca58ba | ||
|
|
9e4cd2cf1a | ||
|
|
3711e0054d | ||
|
|
2e9f6cf270 | ||
|
|
c5868fa544 | ||
|
|
274986ad9c | ||
|
|
bcc9b06ac4 | ||
|
|
8f3d668789 | ||
|
|
358ac431a6 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@ comply
|
||||
output
|
||||
dist
|
||||
.envrc
|
||||
bindata.go
|
||||
@@ -1,6 +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:latest
|
||||
|
||||
# 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.4.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"]
|
||||
289
Gopkg.lock
generated
289
Gopkg.lock
generated
@@ -1,289 +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]]
|
||||
name = "github.com/andygrunwald/go-jira"
|
||||
packages = ["."]
|
||||
revision = "5cfdb85cc91c6299f75b6504a1d0ec174c21be39"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[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/fatih/structs"
|
||||
packages = ["."]
|
||||
revision = "a720dfa8df582c51dee1b36feabb906bde1588bd"
|
||||
version = "v1.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/trivago/tgo"
|
||||
packages = [
|
||||
"tcontainer",
|
||||
"treflect"
|
||||
]
|
||||
revision = "e4d1ddd28c17dd89ed26327cf69fded22060671b"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/urfave/cli"
|
||||
packages = ["."]
|
||||
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
|
||||
version = "v1.20.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/xanzy/go-gitlab"
|
||||
packages = ["."]
|
||||
revision = "79dad8e74fd097eb2e0fd0883f1978213e88107a"
|
||||
version = "v0.10.7"
|
||||
|
||||
[[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 = "50dc710fa4b581d4fd6907e0e3337c53c3d530e46c53aa71ef9f8e80d3a54d8b"
|
||||
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
|
||||
31
Makefile
31
Makefile
@@ -3,10 +3,9 @@ GO_SOURCES := $(shell find . -name '*.go')
|
||||
THEME_SOURCES := $(shell find themes)
|
||||
|
||||
assets: $(THEME_SOURCES)
|
||||
@go get github.com/jteeuwen/go-bindata/...
|
||||
@go get github.com/elazarl/go-bindata-assetfs/...
|
||||
@go install github.com/elazarl/go-bindata-assetfs
|
||||
go-bindata-assetfs -o bindata.go -pkg theme -prefix themes themes/...
|
||||
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.go internal/theme/themes_bindata.go
|
||||
|
||||
comply: assets $(GO_SOURCES)
|
||||
@@ -40,7 +39,7 @@ clean:
|
||||
install: assets $(GO_SOURCES)
|
||||
go install github.com/strongdm/comply
|
||||
|
||||
push-assets: is-clean export-example assets
|
||||
push-assets: is-clean assets
|
||||
git commit -am "automated asset refresh (via Makefile)"
|
||||
git push
|
||||
|
||||
@@ -52,16 +51,6 @@ else
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
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
|
||||
cp example/templates/* themes/comply-blank/templates
|
||||
cp example/*.md themes/comply-soc2
|
||||
cp example/*.md themes/comply-blank
|
||||
|
||||
docker:
|
||||
cd build && docker build -t strongdm/pandoc .
|
||||
docker push strongdm/pandoc
|
||||
@@ -113,14 +102,18 @@ release: release-env dist release-deps
|
||||
@echo "version $(VERSION) sha $(SHA)"
|
||||
cd $$COMPLY_TAPDIR && ./update.sh $(VERSION) $(SHA)
|
||||
|
||||
patch-release: release-env push-assets patch release
|
||||
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:"}' https://hooks.slack.com/services/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
|
||||
|
||||
minor-release: release-env push-assets minor release
|
||||
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:"}' https://hooks.slack.com/services/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
|
||||
|
||||
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
|
||||
@@ -134,7 +127,7 @@ minor: clean gitsem
|
||||
release-deps: gitsem gh-release
|
||||
|
||||
gitsem:
|
||||
go get -u github.com/Clever/gitsem
|
||||
go install github.com/Clever/gitsem
|
||||
|
||||
gh-release:
|
||||
go get -u github.com/aktau/github-release
|
||||
go install github.com/aktau/github-release
|
||||
41
README.md
41
README.md
@@ -77,17 +77,56 @@ COMMANDS:
|
||||
todo list declared vs satisfied compliance controls
|
||||
help, h Shows a list of commands or help for one command
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
## Ticketing Integrations:
|
||||
- Jira
|
||||
- Github
|
||||
- Gitlab
|
||||
|
||||
## Configuring 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.
|
||||
|
||||
|
||||
|
||||
|
||||
## 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 http://github.com/strongdm/comply
|
||||
$ go get github.com/strongdm/comply
|
||||
$ cd $GOPATH/src/github.com/strongdm/comply ; go get ./...
|
||||
$ make
|
||||
$ cd example
|
||||
|
||||
@@ -1,10 +1,30 @@
|
||||
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: XXX
|
||||
username: strongdm
|
||||
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
|
||||
|
||||
@@ -17,6 +17,78 @@ majorRevisions:
|
||||
|
||||
# Control Environment Narrative
|
||||
|
||||
Here we narrate why our control environment satisfies the control keys listed in the YML block
|
||||
The following provides a description of the control structure of {{.Name}}.
|
||||
|
||||
# Template Coming Soon
|
||||
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,4 +9,39 @@ majorRevisions:
|
||||
|
||||
Here we describe the key products marketed by our organization
|
||||
|
||||
# Template Coming Soon
|
||||
# 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
|
||||
@@ -15,4 +15,99 @@ majorRevisions:
|
||||
|
||||
Here we narrate why our org satisfies the control keys listed in the YML block
|
||||
|
||||
# Template Coming Soon
|
||||
# {{.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
|
||||
|
||||
@@ -8,7 +8,8 @@ majorRevisions:
|
||||
- date: Jun 1 2018
|
||||
comment: Initial document
|
||||
---
|
||||
#Purpose and Scope
|
||||
|
||||
# Purpose and Scope
|
||||
|
||||
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).
|
||||
|
||||
|
||||
49
go.mod
Normal file
49
go.mod
Normal file
@@ -0,0 +1,49 @@
|
||||
module github.com/strongdm/comply
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/Clever/gitsem v1.0.4
|
||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||
github.com/aktau/github-release v0.8.1
|
||||
github.com/andygrunwald/go-jira v1.12.0
|
||||
github.com/containous/go-bindata v1.0.0
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||
github.com/docker/docker v1.13.1
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/github-release/github-release v0.8.1 // indirect
|
||||
github.com/gohugoio/hugo v0.75.0
|
||||
github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/hashicorp/go-retryablehttp v0.6.7 // indirect
|
||||
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 // indirect
|
||||
github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 // indirect
|
||||
github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8 // indirect
|
||||
github.com/lunixbochs/vtclean v1.0.0 // indirect
|
||||
github.com/manifoldco/promptui v0.7.0
|
||||
github.com/mattn/go-colorable v0.1.7 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/nanobox-io/golang-scribble v0.0.0-20190309225732-aa3e7c118975
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
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/trivago/tgo v1.0.7 // indirect
|
||||
github.com/urfave/cli v1.22.4
|
||||
github.com/voxelbrain/goptions v0.0.0-20180630082107-58cddc247ea2 // indirect
|
||||
github.com/xanzy/go-gitlab v0.30.1
|
||||
github.com/yosssi/ace v0.0.5
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
|
||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
|
||||
gopkg.in/blang/semver.v1 v1.1.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
"github.com/strongdm/comply/internal/jira"
|
||||
"github.com/strongdm/comply/internal/gitlab"
|
||||
"github.com/strongdm/comply/internal/jira"
|
||||
"github.com/strongdm/comply/internal/plugin/github"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
@@ -7,8 +7,15 @@ import (
|
||||
)
|
||||
|
||||
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(pandocMustExist, cleanContainers),
|
||||
}
|
||||
|
||||
@@ -33,10 +33,11 @@ func SetProjectRoot(dir string) {
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
Name string `yaml:"name"`
|
||||
Pandoc string `yaml:"pandoc,omitempty"`
|
||||
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
|
||||
|
||||
@@ -5,21 +5,21 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
const (
|
||||
cfgDomain = "domain"
|
||||
cfgToken = "token"
|
||||
cfgRepo = "repo"
|
||||
cfgDomain = "domain"
|
||||
cfgToken = "token"
|
||||
cfgRepo = "repo"
|
||||
)
|
||||
|
||||
var prompts = map[string]string{
|
||||
cfgDomain: "Fully Qualified GitLab Domain",
|
||||
cfgToken: "GitLab Token",
|
||||
cfgRepo: "GitLab Repository",
|
||||
cfgDomain: "Fully Qualified GitLab Domain",
|
||||
cfgToken: "GitLab Token",
|
||||
cfgRepo: "GitLab Repository",
|
||||
}
|
||||
|
||||
// Prompts are human-readable configuration element names
|
||||
@@ -63,10 +63,10 @@ func (g *gitlabPlugin) Configured() bool {
|
||||
|
||||
func (g *gitlabPlugin) Links() model.TicketLinks {
|
||||
links := model.TicketLinks{}
|
||||
links.AuditAll = fmt.Sprintf("%s/%s/issues?scope=all&utf8=✓&state=all&label_name[]=audit", g.domain, g.reponame)
|
||||
links.AuditOpen = fmt.Sprintf("%s/%s/issues?scope=all&utf8=✓&state=opened&label_name[]=audit", g.domain, g.reponame)
|
||||
links.ProcedureAll = fmt.Sprintf("%s/%s/issues?scope=all&utf8=✓&state=all&label_name[]=procedure", g.domain, g.reponame)
|
||||
links.ProcedureOpen = fmt.Sprintf("%s/%s/issues?scope=all&utf8=✓&state=opened&label_name[]=procedure", g.domain, g.reponame)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -99,13 +99,33 @@ func getCfg(cfg map[string]interface{}, k string) (string, error) {
|
||||
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 := g.api().Issues.ListProjectIssues(g.reponame, options)
|
||||
|
||||
issues, err := getProjectIssues(g, options)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error during FindOpen")
|
||||
}
|
||||
@@ -123,10 +143,9 @@ func (g *gitlabPlugin) FindByTagName(name string) ([]*model.Ticket, error) {
|
||||
Labels: []string{name},
|
||||
}
|
||||
|
||||
issues, _, err := g.api().Issues.ListProjectIssues(g.reponame, options)
|
||||
|
||||
issues, err := getProjectIssues(g, options)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error during FindOpen")
|
||||
return nil, errors.Wrap(err, "error during FindByTagName")
|
||||
}
|
||||
|
||||
return toTickets(issues), nil
|
||||
@@ -137,10 +156,11 @@ func (g *gitlabPlugin) LinkFor(t *model.Ticket) string {
|
||||
}
|
||||
|
||||
func (g *gitlabPlugin) Create(ticket *model.Ticket, labels []string) error {
|
||||
options := &gitlab.CreateIssueOptions{
|
||||
Title: gitlab.String(ticket.Name),
|
||||
Description: gitlab.String(ticket.Body),
|
||||
Labels: labels,
|
||||
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
|
||||
@@ -164,10 +184,19 @@ func toTicket(i *gitlab.Issue) *model.Ticket {
|
||||
|
||||
for _, l := range i.Labels {
|
||||
if l == "audit" {
|
||||
t.SetBool("audit")
|
||||
t.SetBool("comply-audit")
|
||||
}
|
||||
if l == "procedure" {
|
||||
t.SetBool("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
|
||||
|
||||
@@ -16,6 +16,7 @@ const (
|
||||
cfgPassword = "password"
|
||||
cfgURL = "url"
|
||||
cfgProject = "project"
|
||||
cfgTaskType = "taskType"
|
||||
)
|
||||
|
||||
var prompts = map[string]string{
|
||||
@@ -23,6 +24,7 @@ var prompts = map[string]string{
|
||||
cfgPassword: "Jira Password",
|
||||
cfgURL: "Jira URL",
|
||||
cfgProject: "Jira Project Code",
|
||||
cfgTaskType: "Jira Task Type",
|
||||
}
|
||||
|
||||
// Prompts are human-readable configuration element names
|
||||
@@ -40,6 +42,7 @@ type jiraPlugin struct {
|
||||
password string
|
||||
url string
|
||||
project string
|
||||
taskType string
|
||||
|
||||
clientMu sync.Mutex
|
||||
client *jira.Client
|
||||
@@ -66,7 +69,7 @@ func (j *jiraPlugin) Get(ID string) (*model.Ticket, error) {
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) Configured() bool {
|
||||
return j.username != "" && j.password != "" && j.url != "" && j.project != ""
|
||||
return j.username != "" && j.password != "" && j.url != "" && j.project != "" && j.taskType != ""
|
||||
}
|
||||
|
||||
func (j *jiraPlugin) Links() model.TicketLinks {
|
||||
@@ -93,6 +96,9 @@ func (j *jiraPlugin) Configure(cfg map[string]interface{}) error {
|
||||
if j.project, err = getCfg(cfg, cfgProject); err != nil {
|
||||
return err
|
||||
}
|
||||
if j.taskType, err = getCfg(cfg, cfgTaskType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -134,7 +140,7 @@ func (j *jiraPlugin) Create(ticket *model.Ticket, labels []string) error {
|
||||
i := jira.Issue{
|
||||
Fields: &jira.IssueFields{
|
||||
Type: jira.IssueType{
|
||||
Name: "Task",
|
||||
Name: j.taskType,
|
||||
},
|
||||
Project: jira.Project{
|
||||
Key: j.project,
|
||||
@@ -163,8 +169,8 @@ func toTickets(issues []jira.Issue) []*model.Ticket {
|
||||
func toTicket(i *jira.Issue) *model.Ticket {
|
||||
t := &model.Ticket{Attributes: make(map[string]interface{})}
|
||||
t.ID = i.ID
|
||||
t.Name = i.Fields.Description
|
||||
t.Body = i.Fields.Summary
|
||||
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)
|
||||
|
||||
@@ -87,7 +87,10 @@ func GetPlugin(ts TicketSystem) TicketPlugin {
|
||||
}
|
||||
cfgStringed[kS] = v
|
||||
}
|
||||
tp.Configure(cfgStringed)
|
||||
err := tp.Configure(cfgStringed)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Configuration error `%s` in project YAML", err))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ package github
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
@@ -71,8 +73,8 @@ 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%%3Aprocedure", g.username, g.reponame)
|
||||
links.ProcedureOpen = fmt.Sprintf("https://github.com/%s/%s/issues?q=is%%3Aissue+is%%3Aopen+label%%3Acomply+label%%3Aprocedure", 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
|
||||
}
|
||||
|
||||
@@ -95,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)
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"os/exec"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/strongdm/comply/internal/config"
|
||||
"github.com/strongdm/comply/internal/model"
|
||||
@@ -53,6 +55,40 @@ func renderToFilesystem(wg *sync.WaitGroup, errOutputCh chan error, data *render
|
||||
}(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()
|
||||
|
||||
@@ -89,6 +125,11 @@ func preprocessDoc(data *renderData, pol *model.Document, fullPath string) error
|
||||
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
|
||||
@@ -104,6 +145,8 @@ foot-content: "%s confidential %d"
|
||||
%s
|
||||
|
||||
\newpage
|
||||
%s
|
||||
|
||||
%s`,
|
||||
pol.Name,
|
||||
cfg.Name,
|
||||
@@ -114,6 +157,7 @@ foot-content: "%s confidential %d"
|
||||
satisfiesTable,
|
||||
revisionTable,
|
||||
body,
|
||||
gitApprovalInfo,
|
||||
)
|
||||
err = ioutil.WriteFile(fullPath, []byte(doc), os.FileMode(0644))
|
||||
if err != nil {
|
||||
|
||||
@@ -15,7 +15,10 @@ import (
|
||||
|
||||
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
|
||||
@@ -74,7 +77,7 @@ 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()
|
||||
}
|
||||
@@ -82,7 +85,7 @@ func html(output string, live bool, errCh chan error, wg *sync.WaitGroup) {
|
||||
if live {
|
||||
if !opened {
|
||||
opened = true
|
||||
open.Run(filepath.Join(".", "output", "index.html"))
|
||||
open.Run(fmt.Sprintf("http://127.0.0.1:%d/", ServePort))
|
||||
}
|
||||
} else {
|
||||
wg.Done()
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -11,6 +13,8 @@ import (
|
||||
"github.com/yosssi/ace"
|
||||
)
|
||||
|
||||
var ServePort int
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
@@ -87,6 +91,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("0.0.0.0:%d", ServePort), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
fmt.Printf("Serving content of output/ at http://127.0.0.1:%d (ctrl-c to quit)\n", ServePort)
|
||||
}
|
||||
// PDF
|
||||
wg.Add(1)
|
||||
|
||||
@@ -45,7 +45,6 @@ func watch(errCh chan error) {
|
||||
}
|
||||
|
||||
http.HandleFunc("/ws", serveWs)
|
||||
go http.ListenAndServe("127.0.0.1:5122", nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ func complyBlankReadmeMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-blank/README.md", size: 1965, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-blank/README.md", size: 1965, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -157,7 +157,7 @@ func complyBlankTodoMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-blank/TODO.md", size: 1429, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-blank/TODO.md", size: 1429, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -277,7 +277,7 @@ func complyBlankTemplatesDefaultLatex() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-blank/templates/default.latex", size: 7649, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-blank/templates/default.latex", size: 7649, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -297,7 +297,7 @@ func complyBlankTemplatesIndexAce() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-blank/templates/index.ace", size: 7596, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-blank/templates/index.ace", size: 7596, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -317,7 +317,7 @@ func complySoc2ReadmeMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/README.md", size: 1965, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/README.md", size: 1965, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -337,7 +337,7 @@ func complySoc2TodoMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/TODO.md", size: 1429, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/TODO.md", size: 1429, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -357,12 +357,12 @@ func complySoc2NarrativesReadmeMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/README.md", size: 96, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/README.md", size: 96, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _complySoc2NarrativesControlMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x90\x31\x4f\xc3\x30\x10\x85\x77\xff\x8a\x27\x31\x07\x91\xb4\x95\x50\x56\xab\x12\x20\xe8\x40\xbb\x30\x9a\xe4\xa0\x47\xe3\x3b\x64\x3b\xa9\xf2\xef\x91\x23\x14\x99\x89\xc9\x4f\x9f\xdf\xb3\xdf\x9d\x38\x4f\x2d\xac\x4a\x0a\x3a\x60\x2f\x13\x07\x15\x4f\x92\x70\x70\x21\xb8\xc4\x13\x19\xd7\x05\x95\xd9\xb7\xb0\xfb\x83\x89\x2e\x71\xfc\x60\x8a\xad\x01\x4e\x47\x9b\x0f\xa0\x82\xb5\xcd\x6d\x5d\xe8\xa6\xd0\x9b\x55\x6f\x0b\xcf\xb6\xf0\xec\x0a\xbe\xfb\xc3\x37\xc6\xbb\x2f\x0d\xaf\x34\x71\x64\x95\xe5\xdb\x0a\xbd\x4b\xd4\xe2\x69\x14\xd4\x68\xee\xea\xfb\x25\xd0\xa9\xcf\xcd\x5b\x3c\x0a\x27\x76\x03\x7a\xed\xc6\x4c\x4c\x55\x55\xc6\xdc\xfc\x33\xa6\x79\xa0\x40\xb8\x12\x64\x41\x84\xeb\x79\x86\x8e\x01\xdd\x6f\x8c\x8a\xd8\xba\x06\xa4\x33\xad\x8e\x0b\xcd\x11\x03\xc7\x44\x3d\x58\x96\xab\xb7\x97\x67\xbc\x0f\xda\x5d\x72\x81\x13\xf9\xef\x21\x3f\x6d\xd5\xb3\x7c\xe2\xa8\x2a\xe6\x27\x00\x00\xff\xff\x49\x83\xc0\x0b\x83\x01\x00\x00")
|
||||
var _complySoc2NarrativesControlMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x56\x4d\x6f\x1b\xc9\x11\xbd\xcf\xaf\x28\x40\xc0\x26\x01\x44\x26\xf6\xee\x02\x81\x6e\x0a\xa5\x04\x0e\xbc\x96\x60\x09\xde\x83\x91\x43\xb1\xa7\x86\xac\xa8\xa7\x6b\xb6\xab\x9b\xf2\x64\xe1\xff\x1e\x54\xf7\x70\x38\xb4\x2d\x38\x97\x9c\x38\xec\x9e\xa9\x8f\xf7\x5e\x7d\x04\xec\xe9\x0a\x36\x12\x52\x14\x0f\xb7\xe1\xc0\x51\x42\x4f\x21\xc1\x3b\x8c\x11\x13\x1f\xa8\x41\x17\x25\x8c\xfd\x15\x6c\x6e\xdf\x35\x8a\x89\xb5\x63\xd2\xab\x06\xe0\xf1\x61\x63\x3f\x00\x2b\xd8\x6c\x5e\xaf\x5f\x2d\x9e\x5f\x2f\x9e\x7f\x9c\x9f\x7f\x5a\xbc\xf3\xd3\xe2\x9d\x9f\x17\xe7\x3f\x9f\x9d\xff\xd8\xf4\xf8\x6f\x89\xef\xe9\xc0\xca\x12\x8a\xdb\x15\xb4\x98\xe8\x0a\xfe\x99\x03\xbc\x82\xd7\x7f\x79\xf5\xd7\xf2\x81\x93\xde\x22\xbf\x82\x37\x81\x13\xa3\x87\x56\x5c\xb6\x93\x66\xb5\x5a\x35\xcd\xc5\x77\xd2\x6c\x1e\xf7\x04\x9d\x78\x2f\xcf\x1c\x76\x30\x44\x39\x70\x4b\x0a\x08\x2d\xa9\x8b\x3c\x24\x96\x00\xd2\x41\xda\x13\xb8\xc9\x94\xa6\x98\x5d\xca\x91\xec\xe2\xf7\xdf\xd7\xef\xb0\xa7\xcf\x9f\xd7\xd5\x18\x87\x64\x2e\xca\x27\xac\x67\x66\x58\x21\x09\x50\xc8\x3d\x45\x4c\x54\x6c\x7a\xd9\xb1\x43\x7f\x09\x83\x78\x76\xe3\x25\x60\x68\x2d\x0c\x47\x6d\x8e\xe8\x8f\x3e\x15\xd2\x1e\x13\x28\xc5\x03\x99\x91\x5e\x02\x27\x89\x27\xef\x7f\x50\xc0\x61\xf0\xec\xb0\xb8\x32\x2b\x2d\x26\x04\x25\x97\x23\xa7\x71\x0d\x9b\x3d\x86\x1d\x29\xe4\xe0\xe4\x40\x91\x5a\xd8\x8e\x16\x82\xd2\xec\x8f\x14\x38\x7c\x3b\xac\x53\x48\x97\x20\x11\x5c\xd6\x24\x3d\x45\xa0\x05\xac\x18\x09\xb0\x6d\x23\xa9\x56\xeb\x91\x7a\x6a\xb9\x44\xa4\xa0\x03\x39\xee\xd8\x59\xf8\xe6\x22\x48\xa2\x16\x5c\x89\x6a\x6d\x4c\xbd\xad\x3e\x8f\x8c\x69\xd3\xcc\xd9\x01\xf5\x83\x97\x51\x41\xe9\x40\x06\xcb\x14\xdf\x02\x1e\xb1\x10\x13\xb9\x64\x67\x1d\xb7\x14\xaa\x1c\x0c\x04\x43\x83\x82\x1a\x63\x41\x62\x8f\x1e\x64\x30\x0a\x26\x6e\x39\x29\x38\x89\x05\x87\x36\xbb\xb4\x6e\x9a\x15\xfc\x82\xa1\xc5\x24\x71\xac\x26\x28\xb8\x38\x56\x1a\x31\x41\x24\x4d\xc5\x2a\x07\xe8\xc5\x4e\xed\x8b\xec\x13\xaf\x3a\x74\x46\x0c\xe6\xb4\xb7\x10\x26\x3e\x3a\x3b\x72\x8e\xb4\x44\xea\xbc\x64\xfb\xb6\x8b\x38\x6b\xa9\x59\xc1\xb5\x4b\x7c\xe0\x34\x16\xcb\x18\xa4\x47\x3f\x1e\x99\x36\x75\x4a\x38\x46\x68\x26\x75\xd4\x44\xbd\x36\x2b\xf8\x90\x7d\xa0\x88\x5b\xf6\xf6\x71\x8f\x01\x77\x54\x08\x19\xa2\xec\x22\xf6\x06\xee\x7d\xe1\xf1\x7f\xc2\xb6\x52\xfe\x7f\x82\x16\x1e\xab\xe2\xcc\x07\x17\xbd\x39\x9f\x5b\xba\x84\x6d\xae\x02\x0a\x92\xc0\x73\xcf\x26\x8e\x24\x57\x4d\xc1\xa5\x00\x77\xac\xe4\x9a\x4a\xb3\x82\xdb\x13\x27\xf3\xd9\x5d\xd7\xb1\x23\x78\x98\x64\x7f\xba\xb8\x47\xd5\x67\x89\xed\xe2\xa4\xe6\xf9\x18\x91\x83\xc1\x3b\x5f\x7c\xa0\xd0\x4a\x3c\xfd\xff\x55\xe2\x93\x26\x5c\x3a\x32\x44\x4f\x45\xfa\x2d\x54\xf7\xa8\x50\x2a\x5d\xb2\x82\xba\x3d\xb5\xd9\x53\xbb\x2c\xb5\x45\x19\x1b\x8a\x29\x87\xda\x12\xa8\xeb\xc8\x94\x40\xc1\xb2\x96\x0e\x24\xec\xc4\x02\x3c\xd6\xf2\x4c\x4d\xed\x16\x56\xe4\xd1\xb0\x94\x0e\xe8\x40\x21\xad\xda\x68\x5f\x7f\xe1\x2b\x92\x0e\x62\x7e\x64\x36\xb4\x8a\xe4\xd1\x80\x2e\x9f\xa9\x75\xb0\xbb\x9b\xbb\x2b\xf8\x3b\x07\xf4\xfc\x1f\x9a\xda\x83\x67\x4d\xda\x34\x17\x17\xf0\x30\xe7\x31\x03\x6c\x11\x5c\xe7\x96\xd3\x0c\x08\xa9\x91\x66\xcd\x9b\x9e\x8f\xdc\x7d\xfc\x2d\x63\x4c\x14\xfd\xf8\xaf\xd3\xdd\x6c\xe3\xad\xec\x14\x3e\x3e\x13\x3d\x9d\xdd\x6f\xc6\x2d\x45\x78\xcf\xfa\x04\xd7\xaa\xa4\x5a\x44\xfd\xc7\x53\x03\x1d\x44\x95\xb7\xde\x3a\x73\x3f\x44\xe9\x59\x09\xd4\x51\xc0\xc8\xa2\x7f\xfa\xb6\xd3\x1b\x53\xed\xc6\xa3\xaa\x35\xa3\x4a\xea\xf9\x8b\x7f\x43\xf7\x94\x07\x78\x24\x4d\x86\xfa\xf9\xe5\x0d\x2b\x6a\xb2\xb0\xa8\xb4\xd1\xf1\xf4\x9e\x52\xcf\x2b\x0c\x21\xa3\x5f\xfa\xa3\x03\x3b\x52\xf8\x61\x29\xa3\x17\x00\xf9\x01\x36\x9e\x30\xc2\x5b\x79\x5e\xdd\x47\x96\x02\xce\xb5\xa7\x98\xce\xe0\xb9\x1e\x06\x3f\xc2\xdd\x03\xdc\x63\x72\x7b\x52\xf8\xd8\x4b\x48\xfb\x7a\xf9\x81\x22\x77\x63\x4d\xf3\x86\x75\x10\xb5\x92\x2e\x01\xdb\x60\x3a\x69\xf8\x8b\x10\x36\x12\xac\x40\x4f\xa4\xcc\x75\xf1\xf1\xab\x9c\xe6\x77\x7e\x39\x35\xa7\xa2\x03\x0b\xd5\xfe\x6c\xac\x4f\xec\x72\xfc\x16\xbc\xf7\x14\x28\x4d\x37\x86\xdd\xd2\xfe\xaf\x7b\x4e\xb4\x95\x4f\x27\x0f\x93\xc7\xc5\x3b\x0f\x77\x9b\xd7\x93\xe2\xe6\x53\xd3\xe6\x6d\x91\xfe\x4d\x95\xfe\x77\xe5\x79\x17\xb6\x82\xb1\x85\xdb\xd2\xfc\x88\x6a\xeb\xf8\xea\xec\x4d\x38\x18\xbd\x3b\x53\xdb\x6c\xb3\xa4\xf9\xd2\xe5\x9b\xe0\x4a\x87\xb4\x16\xf1\x7e\x31\xff\x96\xbd\x21\xab\x95\xe4\x9e\x40\x72\x72\xd2\xd7\xd2\xb5\xff\xd8\x49\x2c\xad\x9b\x25\xd8\x70\x3c\xb6\xe0\xe5\x52\x50\xab\xb9\x76\xe1\x6e\x04\xdd\x4b\x34\x23\x1c\x76\xf3\xf4\xa6\x4f\x5c\x35\x79\xdc\x58\x16\x53\x7a\x0d\x77\xc1\xd1\xf1\x7b\xa6\xf6\x72\xaa\xf2\xa3\x21\xdb\x7e\x22\xcd\xb3\xbb\x4e\x72\xee\xcb\x6a\x14\x76\x5f\xd9\xfe\x32\xb8\xda\x93\x5c\x24\x2c\x6f\x05\x7a\x7e\x31\x0d\xeb\x90\x44\x2d\xb5\xeb\xba\xa8\xf5\x7d\x0e\x53\x49\x9e\xc1\xe5\xe6\x1b\x52\x88\xe4\xe9\x80\x21\xd9\xf8\xb4\x81\x53\x74\x14\x69\x87\xb1\x35\x7f\x96\x7e\x97\x43\x19\x91\x65\x66\x4e\xc0\x6e\xe5\x40\xa7\x40\x9e\x39\xed\xcb\xa6\x16\x03\xfa\x3a\xc3\x3e\x4d\x7f\x06\x8c\xa9\x34\x53\x5b\xa2\x00\x75\x55\x43\x84\x2d\x2a\xd7\x0c\xd0\x39\x99\x9c\x09\x58\x41\xe7\xb2\x26\x44\xfa\x2d\x73\x65\xcf\x3a\xe9\xc5\x05\xbc\x99\x1c\xbc\x98\xcb\x91\x9e\xa3\x0c\x2e\xa7\xa9\xcf\x47\x18\xcf\x16\xa8\x63\xbc\x7e\x84\xac\x73\xae\xf3\xee\x6a\x9b\x54\x20\xaf\x65\x64\x3e\x78\x74\x4f\x36\x22\x7b\x64\xdf\xac\xe0\x1f\x9c\xf6\x79\x0b\x89\xdd\x13\x19\x2f\xb5\x62\x3e\x7d\x27\xbe\x19\xeb\x29\xd0\x79\x5e\x2c\xb1\xb7\x95\xf6\x4b\xf0\xea\x54\x2f\x33\x6b\x8f\x91\xf6\xe2\x5b\x8a\x7a\x39\xaf\x8d\xf6\x68\x26\xcb\xae\xa4\x97\xc6\x5f\xf6\x58\x9f\x2d\xef\x9d\xb5\xd6\xba\x54\x9a\x4c\x8b\xcd\x59\x2d\xe7\x04\x1c\xed\xe4\x89\xc8\xd9\xd4\xf8\xe7\x13\x37\xb2\xf5\x56\xa6\x2c\x61\xfd\xdf\x00\x00\x00\xff\xff\xd5\x1b\xb6\x85\xfd\x0c\x00\x00")
|
||||
|
||||
func complySoc2NarrativesControlMdBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
@@ -377,7 +377,7 @@ func complySoc2NarrativesControlMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/control.md", size: 387, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/control.md", size: 3325, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -397,12 +397,12 @@ func complySoc2NarrativesOrganizationalMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/organizational.md", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/organizational.md", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _complySoc2NarrativesProductsMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x44\xcd\xb1\x4e\x03\x31\x10\x84\xe1\xde\x4f\x31\x12\xf5\x49\x84\x0a\xb9\xa5\x01\x8a\x28\xe2\x78\x81\x8d\x3d\x0a\x4b\xe2\xdd\x68\xed\x3b\x74\x3c\x3d\x4a\x81\xd2\x8e\x46\xff\x67\xd2\x98\x71\x08\xaf\x4b\x19\x1d\x62\x15\x33\x63\xd5\xc2\x8e\xbd\x44\xc8\xd0\x95\x49\x4a\xb8\x6d\x2d\xe3\x30\xef\x53\x93\x6f\x8f\x0f\xae\xda\xd5\xad\xe7\x04\x4c\xa8\x32\x98\xf1\xbe\x18\x76\x78\x7a\xdc\x3d\x27\x00\x28\xde\x1a\x6d\x64\xbc\x99\x0e\x95\x0b\xaa\x97\xe5\xb6\xa4\x69\x9a\x52\x7a\xb8\xb3\x77\x29\xbd\x32\x88\x1f\xa2\xb2\x97\xd0\x23\x31\xbe\x88\x33\x37\x5c\xff\xcf\x4d\xe2\xcc\xc1\x8a\xe3\x06\x5f\x02\x1e\x27\x31\xfd\x95\xa1\x6e\xb7\xea\x27\xdb\xf5\x22\x83\x78\xf1\xa6\x76\xc2\xec\x6e\xe9\x2f\x00\x00\xff\xff\x2c\x6f\xb1\xc2\xe8\x00\x00\x00")
|
||||
var _complySoc2NarrativesProductsMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\x52\xcb\x6e\xdb\x40\x10\xbb\xef\x57\x10\xf0\x35\x0e\x9a\x9e\x0a\xdf\xd2\xf6\xd0\x14\x69\x62\xd8\x5f\xb0\x5e\xd1\xf2\xd4\xd2\xae\x30\xb3\xb2\xa1\x7e\x7d\x21\xd5\x7a\x24\xcd\x51\x1c\x8a\x1c\x72\x27\xfa\x9a\x1b\x6c\x35\x15\x6d\xc8\x06\x1f\x0b\xec\xa9\x17\x09\x34\xbc\x78\x55\x9f\xe5\x42\xe7\x83\xa6\xd8\xd5\x1b\x6c\xf7\x2f\xae\xf6\xbf\x93\xee\x78\x11\x93\x14\x6d\xe3\x80\x35\x0a\x9f\xb9\xc1\xcf\x36\xe2\x01\x9f\x3f\x3d\x7c\x71\x00\x10\x52\x5d\x33\xe6\x0d\x9e\xa2\x64\xf1\x15\x8a\x14\xda\x1e\x71\xeb\xf5\xda\xb9\xd5\x6c\x3b\x3b\xb9\x1f\x54\xe2\x4a\x14\xb4\xa0\x72\x20\xf2\x89\x38\xb3\x43\x33\x92\x6b\xaf\x67\x66\x16\x38\x74\x48\xad\x22\x69\xe9\xa3\xfc\xf1\x59\x52\x5c\xaa\x3a\xb7\x9a\x3e\xf0\xe0\xdc\xeb\xa5\x0f\xc6\x2b\xd2\x71\x14\xeb\xe1\xd5\x6a\x85\x47\x0d\x27\xc9\x0c\xb9\x55\x3a\xf7\x55\x85\x47\xf8\x19\xeb\x57\x17\x0b\xad\xf5\x89\x3f\xf8\x7d\xcf\xd0\xaa\xe4\x0e\xdf\x52\x34\x29\xa8\xc3\x2e\xe6\xdc\xbe\x61\x90\xa3\x04\xd8\xc8\x08\x6f\x18\x38\x26\x9d\xc5\xee\xb1\xe3\x91\x8a\x9c\xd0\xa4\x4a\x82\xd0\xee\xfa\x69\x60\xd1\x2a\x0d\x27\x2a\xef\xfb\x84\x03\x8d\x31\xf0\x5f\xc6\xa9\x3d\x73\xee\x59\x2c\x43\x59\xf1\xe2\x63\x46\x9c\x26\x83\xd0\xc1\x1f\xaa\x0e\x12\x43\xd5\x16\x12\x4b\xf7\xba\x68\xce\x57\x8b\x57\x98\x02\x2d\xa0\xce\x32\xeb\xe5\x4b\xf5\xed\xde\xd6\x7c\xef\xfb\x66\xfd\xf7\xae\x8f\x4d\x53\x49\x18\x4c\xe7\xe6\x06\xa5\xce\x7d\xf7\xd9\x07\xc6\x4c\x1d\x91\xe7\x54\xe2\x97\x8f\xbe\x64\x7f\x39\x23\xba\xf5\x66\xd7\xa4\xc5\xf8\x3d\xe9\x3c\xc5\x20\x45\x4f\xdc\xd1\x9a\x14\x8d\x23\x63\x27\x76\xc6\xa3\x19\xcd\x96\x42\xb7\x1b\xb9\x55\xfc\x5f\x8e\x69\xf2\x51\x12\xf8\x10\x68\x06\x65\x7f\x56\x77\x68\x7c\x0e\x27\x89\xe5\x1d\x7c\x45\xcd\xa8\x53\x94\x9c\x74\x40\xaa\x54\xce\x3c\x46\x64\x5a\x96\x58\xfe\x0d\x00\x00\xff\xff\x5a\x81\xee\x7e\x7f\x03\x00\x00")
|
||||
|
||||
func complySoc2NarrativesProductsMdBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
@@ -417,12 +417,12 @@ func complySoc2NarrativesProductsMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/products.md", size: 232, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/products.md", size: 895, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _complySoc2NarrativesSecurityMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\xb1\x4e\xc3\x40\x0c\x86\xf7\x7b\x8a\x5f\x62\x4e\x45\x3b\xb4\x28\x1b\x8a\x90\x00\x41\x07\xd2\x85\xf1\xb8\x98\xc6\x34\x67\x23\x9f\xd3\x2a\x6f\x8f\x92\xa1\xea\xc6\xe4\x4f\xbf\xe5\xcf\xb6\xc4\x4c\x35\x5a\x4a\xa3\xb1\x4f\x78\xb4\xd4\xb3\x53\xf2\xd1\x08\xfb\x68\x16\x9d\xcf\x14\x62\x32\x95\x29\xd7\x68\x9f\xf6\xa1\x44\xe7\xf2\xcd\x54\xea\x00\x1c\xda\x66\x2e\x40\x85\xa6\xd9\xae\xb6\x37\xbc\xbb\xf2\x6e\xb5\xbe\xe1\x4d\xc8\xf1\x47\xed\x83\xce\x5c\x58\x65\xd1\x54\xe8\xa2\x53\x8d\xd7\x51\xb0\xc6\xe6\x7e\xfd\xb0\x0c\x24\xcd\x99\xc4\x6b\xbc\x08\x3b\xc7\x01\x9d\xa6\x71\x4e\x42\x55\x55\x21\xdc\xfd\x7b\x78\x78\x26\x23\x5c\x08\xb2\x44\x84\x4b\x3f\x41\x47\x83\xda\x11\xd7\x47\xe0\x3d\x21\xa9\xb8\xe9\x80\x13\x4d\x05\x03\x17\xa7\x0e\x2c\x4b\xeb\xf3\xfd\x0d\x5f\x83\xa6\xd3\xbc\xf2\x40\xf9\x77\x98\x55\x8d\x66\x96\x23\x5a\x55\x09\x7f\x01\x00\x00\xff\xff\x71\xb6\xff\x0e\x47\x01\x00\x00")
|
||||
var _complySoc2NarrativesSecurityMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x57\x5f\x6f\xe3\xc6\x11\x7f\xe7\xa7\x18\xc0\x40\x0a\x38\x96\xae\x97\x87\xa4\xf0\x9b\xaa\xbb\x22\x6e\x7d\x67\xc3\x32\x72\xe8\xe3\x88\x1c\x89\x5b\x2d\x77\xd8\x99\xa5\x54\x26\xca\x77\x2f\x66\x97\x94\x68\xdd\xf9\x82\xb4\xc8\x9d\x01\x2d\x97\xcb\xf9\xf7\x9b\xf9\xcd\x6c\xc0\x86\x6e\x61\x45\x65\x27\x2e\xf6\xb0\x90\xb2\x76\x91\xca\xd8\x09\xc1\x47\x14\xc1\xe8\xf6\x54\x60\x29\x1c\xfa\xe6\x16\x56\xef\x3f\x16\x8a\xd1\xe9\xc6\x91\xde\x16\x00\xcf\xab\xa5\xfd\x00\xcc\x60\xb9\xfc\x7e\xfe\xfd\x64\xfd\xc3\x69\xfd\xc3\xfc\xed\x64\xfd\x5d\xd1\xe0\xbf\x58\x9e\x68\xef\xd4\x71\x48\x62\x66\x50\x61\xa4\x5b\xf8\x7b\x17\xe0\x2d\x7c\xf7\xe7\xb7\x7f\x49\x1f\x94\xdc\x34\x14\xe2\x2d\xdc\x05\x17\x1d\x7a\xa8\xb8\xec\x6c\xa7\x98\xcd\x66\x45\x71\xf5\x9b\x86\x17\x3f\x92\x10\x1c\x08\x42\xda\x22\x38\xd4\x3d\x70\x27\xc0\xb2\x85\x93\x23\x10\x6b\x82\x92\x43\x14\xf6\xb0\xa3\x5e\xc1\x3b\x8d\x54\x81\x0b\xe9\xd5\x3f\x3f\xdc\xc3\xda\x73\xb9\x33\x95\xbf\xfc\x32\xff\x88\x0d\xfd\xfa\x2b\x3c\x0a\x57\x5d\x19\x5f\xe8\x2e\x8a\x77\xa4\xa5\xb8\x35\x41\x3b\xbc\xc6\xa9\x69\x35\x09\xdd\x00\x35\x6d\x8d\xea\x7e\x76\x61\x0b\x3a\xba\xe0\x9a\xd6\xbb\x12\xa3\xc5\xe4\xa5\xa2\xbb\xb0\x11\xd4\x28\xdd\xa0\xe2\xea\xea\xa4\xfb\xf2\xd5\x67\xda\xdd\x8b\x03\xaf\xa8\x6e\x08\xb5\x13\x32\xb5\x57\x57\xb0\xe8\x62\xcd\xe2\x7e\xa6\x0a\x1e\x49\x94\x43\x20\x5f\x14\x33\xb8\xbe\x5e\x7c\x5a\x81\x30\x47\xc0\xb2\xe4\x2e\xc4\xeb\x6b\x5b\x91\x2a\x38\x85\xad\x60\xb0\xa0\x71\xf0\x3d\x44\x4e\x91\x5b\x3e\x3f\x00\x86\x0a\x96\xef\x1f\x4e\x02\xee\x16\x1f\xbe\xf8\x9d\x7d\xc2\x80\xe0\x5d\xe3\xec\x79\x2b\xdc\xb5\xc0\x1b\xb8\xbe\x7e\x68\x49\x30\xb2\xe8\xf5\x75\x12\x73\x0e\xcd\x6a\xf5\xe3\x6b\xc2\x7e\xa7\xa4\x77\x7f\xfd\x5d\x82\xde\x61\x44\x98\x4a\x33\x54\xee\x9e\x3f\x03\xe4\xac\xa0\xd3\x21\xd3\x36\xec\x3d\x1f\x0c\x80\xd2\x73\x57\x81\x92\xec\x5d\x49\x0a\x1b\x16\x70\x51\xc1\x85\x48\x12\xd0\x5f\x80\x77\x6b\x20\xdc\x3b\x8d\x17\xdf\x15\xc5\x22\x9b\x9d\x83\xae\x74\x29\xd7\xe9\xc9\x03\x03\x4e\x2a\xd3\x3d\x20\x24\xec\xc9\x3c\xb2\xf5\xd9\x56\x6a\x5a\xcf\x3d\x51\x02\xcf\x29\x08\xed\x1d\x1d\xa8\x82\x7f\x77\x28\x91\xc4\xf7\x80\x0a\x07\xf2\xde\x7e\xf7\x0e\x41\x68\xdb\x79\x14\xe0\xb0\x66\x4c\x1a\xde\xf0\x66\x33\xae\x21\xa2\xee\xb2\x83\x81\x0e\x49\x6a\x45\x2d\x4a\xb4\x77\xa3\x32\x9d\xbf\x4c\xfb\x4f\x2c\x3b\x8d\x63\x41\x9c\xf7\x0f\x93\x7d\x40\x2b\x2a\x94\x8a\x82\x79\xb7\x45\x17\x34\x82\xe7\xad\x2b\xd1\x27\x3d\x6d\xdd\x6b\x7e\x88\x11\xcb\x1d\xac\xfb\x0b\x10\xc6\xe4\x4f\xe1\xe5\x84\x68\x2a\x8e\x5e\x23\x35\xd0\x74\x1a\x61\x4d\x70\x70\xb1\x76\x01\x38\x10\x6c\x29\xa4\x43\x1c\x2c\x70\x65\x27\x92\x18\x09\x36\x9d\xf7\xb3\xca\xe9\x0e\x28\x94\xd2\xb7\x76\xc2\x44\xe6\x88\x00\x86\xe8\xf6\x4e\x3a\x7d\x63\xab\x06\xfd\xc1\x6c\x57\xde\x44\x5b\x14\x33\x78\x58\x25\x83\x17\x3f\x01\x76\x91\x1b\x8c\x66\xb6\xef\xa1\x6b\x8d\x1c\xab\xa2\x98\x04\xc4\xa8\xb1\xf5\x0e\x43\x99\x4d\x1b\x80\x1f\x7d\x31\xcc\x68\x8f\xbe\xc3\x5c\x91\x80\x13\xe4\xd6\xa8\x2e\xc5\xfa\x0a\x9e\xa8\xe1\x48\x90\xf3\xa7\x28\x3e\x60\xe8\xbf\x90\x05\x9a\x42\x0e\x92\x0e\xfb\x3e\xcb\x1b\x01\x4f\xd2\x92\xe1\xa5\x31\x45\x19\x2d\xb3\x06\xf6\x31\x43\x53\x06\x8d\x09\x7d\xf7\x3c\xc4\x35\x27\x8d\x01\xa1\xd8\x98\xdd\xb1\xe6\x4a\x2d\x99\x62\xcd\x4a\x13\xd5\x83\x54\x83\x64\x23\xdc\x5c\x24\xea\x09\x5d\xde\x6c\x5c\x49\x37\xe0\xe6\x34\xbf\x81\xca\x89\x59\x32\xe0\x90\xf3\x7e\xa8\x90\x97\xb5\x31\x87\xbb\x68\xc1\x32\xa9\xa3\xce\x3f\x59\xbe\x6b\xcb\x41\xdd\xda\x79\xe3\xc7\xc8\x40\xc1\x02\x0b\xb1\xc6\x98\x19\x0e\xcf\x2c\xd9\x8e\x2c\x69\x35\x3e\x31\x4e\x48\xb9\x13\xab\x40\x0b\xc2\x60\xc2\xf9\xf5\x10\x89\x94\xf5\x43\x05\x3f\xa5\x3a\x9b\x16\xf4\xf9\xf8\x25\x93\xaf\x39\xd6\xe7\xc8\xa6\x54\xcf\x51\xbf\x79\xad\x62\x13\x12\x58\x5a\x67\x34\x4b\x25\x57\x8f\xc1\xba\xa7\x6a\x0e\x8b\x60\x67\xb8\x41\x6f\x3d\x31\xbf\x6a\x59\x46\x6e\x36\xac\xc6\x86\x11\x09\x9b\x54\xcd\x9b\x4e\x62\x4d\x02\x2e\xec\x49\xa3\xdb\xa6\xe4\x9c\xc3\xa7\x9a\xc2\x04\x43\x8d\x28\x11\x58\x86\xa2\xbf\x01\x0c\xaf\x11\x45\x2b\x5c\x52\x65\xa1\x76\x3a\x14\x69\xd6\xdf\x0a\xe7\x81\x61\x90\x73\x7a\xc4\xb6\x15\x6e\xc5\x59\x7b\x1f\xfa\xd2\x10\xeb\x14\xd9\x47\x0a\x14\x87\x72\x7d\x36\x1b\xc3\x76\x4a\x26\x36\x62\x38\xd5\xcc\x25\x01\xe8\x3f\x43\x3c\xdb\xc9\x67\x91\x34\xa6\xa4\xb7\xbf\xd0\xa1\x1f\x4a\x08\x16\xde\xc3\xc6\x05\x33\x3c\x07\xcc\x35\x0d\x55\x66\x89\xef\xcf\x08\x24\xf0\xab\x4a\x48\x75\x12\xca\x34\x7c\x60\x39\xd2\xc8\xd0\x2d\xdf\x2c\xdf\x3f\x5c\xd0\xe0\xe3\x98\xe2\xe3\xb0\x33\x35\xbf\x46\x4d\x9c\x74\xaa\x03\xcf\x79\x84\xb8\xb1\xe1\x65\x85\x01\xfe\x26\x18\x4a\xa7\x25\xdf\xc0\x72\x31\x87\x7f\x50\x0f\x4e\xb5\x4b\xcc\x61\x89\x2f\x58\xee\xa8\x1a\x69\xf1\x21\x95\xd1\xe7\x3a\xe1\x91\xbd\x2b\x7b\xb8\xa7\x6a\x4b\x32\x1f\xcf\xa5\x61\xc9\x1c\xc7\xaa\x72\xa6\x36\x11\x56\x4d\xfe\x24\xd0\x93\x2a\xcb\x8d\xc1\xd7\x92\xd8\xac\x81\x01\xb7\x64\x43\xdc\x4d\x66\x8d\x4e\x23\x57\x36\xdc\x69\xc4\xcd\x66\x0e\xcf\x89\xc9\x4e\x92\x03\xc7\xff\xd5\xc8\x73\x98\xb2\x52\xd1\x91\xb5\x4e\xf0\x4c\xda\x43\x2e\xb9\x56\xdc\xde\x79\xda\xa6\x6e\xf4\x5a\xf1\xa5\x8e\x6a\x81\xa6\x6a\x6c\x0c\x8b\x4f\xab\xa9\xc2\x8a\x49\x93\xe9\x35\xee\xe9\x33\x25\x91\xed\xfc\x85\xd0\x04\xfb\x93\xb5\x8f\x85\x2a\xa9\xa6\x39\x77\x3a\x3f\xa4\x36\xa0\x69\x42\x58\xf6\x6b\x92\xcb\xc3\x5f\x48\x51\x4b\x02\x96\x8a\xc4\x54\xee\x88\x5a\x68\x71\xd2\x31\x80\xf6\xec\xf7\xa9\x3f\xd7\x42\x18\xc1\x63\xa8\xb4\xc4\x96\x12\x0c\x93\x26\x99\x28\x3e\x55\x79\x88\x2c\xbd\x65\x2c\x56\x7b\x12\x45\x71\x03\xfb\x04\x0e\xb3\xe9\x5e\x16\x69\x9c\xae\xa7\xcc\x5f\xa7\x59\xc3\x35\x46\x2b\x29\x03\xa7\x0c\x97\x5b\xd2\x62\x22\xe2\x39\x8b\x28\x8a\x97\xc6\x08\xb5\x42\x4a\x21\x66\xde\x7e\xd5\xaa\xc1\x82\xdb\xa2\x38\x66\x49\xc7\x55\xe2\xe3\xe3\x4f\x54\x46\x96\xe3\x33\xca\x96\xe2\xf1\xde\xed\xc8\xbb\x9a\xb9\x3a\xae\x68\x4f\x96\x49\xc7\xe2\x38\xfb\xca\xbf\x6f\xbf\xf2\xf8\xed\xd7\x4e\x0f\xcb\x63\x71\x84\xc9\xff\xe4\xf7\x47\x0e\xb3\xff\xd3\xf7\x57\x10\x98\xf8\xff\x47\x3a\xfe\x5b\x7e\xa6\xf4\xa6\x0d\x09\x85\x32\x5f\x35\xce\x17\x35\x2d\x8a\xe1\x46\x93\x7b\xe5\x6a\x1c\x5d\xcf\x57\xb9\x55\x9e\xc7\x5e\xbb\xe8\xd9\x9d\xc8\xaa\xdf\x99\xac\xf7\xa7\xf9\x6b\xa0\x84\xe2\x9e\xb7\xf0\xe1\xc4\x3c\xe3\xee\x40\x24\x17\xfc\x51\xbc\x98\x8a\xc6\xcd\xd3\xa1\xbb\x50\xba\xca\x84\x3c\xe5\x21\x81\xc6\x13\xd3\xf1\x6c\xd8\x1a\xae\x6a\xb9\xa3\xd9\xa0\xde\xb6\xbe\xb7\x41\xef\x11\x63\x59\x93\x16\xb9\xe1\xc3\x37\xb0\xf4\x84\x02\xf7\x7c\x98\x3d\x8a\xe3\x7c\xa7\xf5\x24\xf1\x74\x64\x98\xd1\x86\xa7\x77\x94\xe3\xf3\xcd\xcb\x29\xf9\xbf\x01\x00\x00\xff\xff\xa2\xda\x57\x64\xcf\x0f\x00\x00")
|
||||
|
||||
func complySoc2NarrativesSecurityMdBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
@@ -437,7 +437,7 @@ func complySoc2NarrativesSecurityMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/security.md", size: 327, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/security.md", size: 4047, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -457,7 +457,7 @@ func complySoc2NarrativesSystemMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/system.md", size: 257, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/narratives/system.md", size: 257, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -477,12 +477,12 @@ func complySoc2PoliciesReadmeMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/README.md", size: 71, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/README.md", size: 71, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _complySoc2PoliciesAccessMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x55\xc1\x6e\x1b\x47\x0c\xbd\xeb\x2b\x08\xe4\xd2\x1a\x91\x5a\xa7\x40\x51\xe8\x96\xba\x05\xec\x02\x45\x0c\x45\x40\xce\xd4\x2c\x57\xcb\x68\x76\xb8\x20\x67\xa5\xca\xa7\xfe\x46\x7f\xaf\x5f\x52\x70\x66\x25\xcb\x6e\xec\xe4\xa4\xdd\x19\x91\x7c\x8f\xef\x91\x9b\xb0\xa7\x25\xbc\x0f\x81\xcc\xe0\x43\xda\x08\x6a\xc3\x69\x0b\x98\x1a\x58\x93\xf6\x9c\x30\xb3\x24\xb8\x97\xc8\xe1\x38\xc3\xa0\x92\x8e\xfd\x12\xde\x7f\x58\xdf\xcf\x0c\x33\x5b\xcb\x64\xcb\x19\xc0\xfa\xe3\x8d\xff\x00\xcc\xe1\xe6\xe6\xe7\xc5\xf5\xc5\xf3\xbb\x8b\xe7\x9f\x66\x3d\x7e\x16\x5d\xd1\x9e\x8d\x25\x95\xd0\x39\x34\x98\x69\x09\x7f\x8c\x09\xae\xe1\xdd\x8f\xd7\xbf\x94\x80\x20\x7d\x4f\x29\x2f\xe1\x2e\x71\x66\x8c\xd0\x48\x18\xfd\x64\x36\x9f\xcf\x67\x6f\xe0\x7e\xd4\x41\x8c\x0a\xd6\x8f\x41\x06\x9a\xcd\x70\x01\xeb\x8e\x60\x98\x6e\xa4\x85\xdc\xb1\xc1\x50\xd0\x43\x16\x68\xa8\xe5\x44\x30\xa8\x04\x6a\x46\x25\xf3\x43\xa9\xbc\x4b\x22\x69\xdb\xfa\x32\x1a\x69\xb9\xcd\x14\xba\xc4\x01\x23\x70\x6a\x15\x2d\xeb\x18\xf2\xa8\x04\x9c\x00\xa1\xc7\x94\x48\x21\x77\x98\xa1\xe7\xc4\x3d\x3f\x78\xd2\x8e\x40\xd9\x76\x8e\x80\x53\x2b\xda\xd7\x36\x46\x31\x03\x51\xa0\xbf\x06\xb1\x51\x69\x01\x13\xe6\x47\x90\x38\x0c\x91\x2b\x2e\x8c\xf1\xe5\xea\x07\xce\x1d\xa7\x52\x49\x74\x8b\x89\x1f\x4a\x89\xaf\x67\x6c\xc7\x18\xe7\x99\xfb\xda\xb8\x01\x35\xd7\x37\xea\x87\x28\x47\x22\x2b\xe7\x41\x52\x56\x0c\x59\xd4\x3c\xe5\x1b\xf8\x15\xc3\x6e\xab\x32\xa6\xa6\x14\xb8\x4b\x20\xda\x38\x73\x39\xf3\xfe\x66\xda\xf0\x5d\xab\xd2\xc3\x46\x72\x07\x9c\x8c\x9b\x8a\x45\xc6\x5c\x9e\x9f\x73\xfa\xfe\xed\xff\x8e\x80\x0d\x94\x22\x63\xca\x20\xb5\x0b\x83\x72\x0a\x3c\xc4\x22\x7b\x24\xb4\xec\x47\x7b\x8e\xb4\xa5\x85\x5b\x5c\xc6\x94\x21\x28\xd5\x04\x85\xbc\x3b\xdc\xac\x40\xa4\x3d\x45\x03\x54\x02\x25\xcb\xca\x21\x53\x53\xcd\x11\x8f\x95\x18\x99\x8c\x1a\xbc\x3f\x1b\x93\x38\x66\x8a\x47\x48\x44\x4d\xfd\xdf\x40\xea\x84\x81\x30\x74\xfe\x62\x92\xfe\xfd\xfb\x1f\x83\xcf\xb2\x81\x66\xcc\x4c\xb6\x80\x4f\x1d\xb9\x67\xdc\x5a\xe5\x4e\x25\xbe\x28\x24\x84\x0e\xd3\x96\xcc\xb9\x17\x97\x57\x02\xf6\x0a\xf0\x1a\xd1\xfc\xa0\xb4\x97\x5d\x45\xd5\x72\x2e\x99\x13\x1d\x6a\x35\x8f\x6e\xd8\x70\x13\xa9\x81\x83\xe3\xf1\x6b\x47\xe4\x3d\xdb\x4f\xde\x7d\x02\x04\x63\x96\x2d\xe5\x8e\xb4\x3a\x61\xda\x05\xee\x82\xab\xdf\x46\xf5\x75\x21\xe7\xcd\xb1\xbc\x9a\x95\xe1\xe5\x05\xdc\x72\xb9\xfb\x13\x13\x6e\x49\x27\x43\x18\xdc\xae\x60\x1c\x24\x41\xc7\x5a\xa4\xc2\x02\xee\xe4\xbe\xc5\x63\xf8\x0a\xa8\x47\x8e\x06\x77\x6b\xa7\x52\xe3\x1d\x5e\xff\x18\x56\x92\x38\xa7\xdc\x11\x6b\xa1\xe8\x20\xa7\x14\x77\xeb\xaa\xb7\x6b\x06\xa1\xa3\xb0\x8b\x6c\xb9\x44\xbf\xde\xcd\x49\xd6\x56\xa6\xc9\x7e\x96\xd7\x77\x8c\x1c\x7c\xee\xa5\xad\x82\x9f\xcc\x01\x4a\x7b\xa6\x43\xcd\x8b\xc3\xa0\xe2\x2d\xc5\x2f\x99\xcf\xfb\x3c\x43\x33\x09\x8c\xee\xb5\x47\x14\xf6\x94\xc2\x41\x74\x67\xc5\x26\x55\x9b\x2f\x17\xce\x02\x46\x19\xc6\xe1\x2c\xe8\xb4\x0a\xce\x1a\x4d\x9b\xed\x55\x91\x92\x64\xf6\x8d\xee\xdd\x2f\xee\xc0\x74\x96\x06\x3a\x34\xd8\x90\x5b\x66\xfa\x32\x50\x73\x81\xf4\x76\x05\x46\xa9\xf1\x56\x1f\x88\x76\xf1\x58\xe5\x03\xa5\x41\x34\x3b\xbe\xbb\x35\xd8\xd8\xf7\xa8\xfc\xe0\x35\x4f\x5a\x4c\x9b\xf6\x9c\xb3\x74\x87\x53\x5d\x75\x27\xf5\x27\xcf\x4e\x3a\x63\xf9\x60\x3d\x6d\xd3\x39\x81\x4d\xd7\xa7\xc9\x6a\x79\x4f\xb0\x19\x8d\x93\x1f\x36\x78\x34\x28\xeb\x47\x29\x10\x0f\x05\x42\xa5\x1d\x2e\x37\xe8\xd5\xa7\xe7\xf4\xa7\x81\x2c\x66\xb0\x97\xc6\xf6\xe5\xd6\x1e\x38\xc6\x93\x89\x6f\x57\xd5\xc2\x35\xa5\x7f\x49\x8a\xc3\x4a\xe4\x45\x3f\xbd\x11\x6e\x00\x8f\x6c\x25\x46\x39\x94\x7a\x86\x3d\x81\x65\x1a\x0c\xd0\x7c\x6b\x46\x4e\xe4\x2d\xab\x68\x9e\x7e\xc5\x2f\x64\xbf\xf8\xec\x9d\x48\xae\x8a\x5d\x5f\x99\x08\xbb\x20\xf4\xbb\x1b\xae\x97\x94\xbb\xb7\x0e\xcb\xff\xe8\x36\x71\x74\xd5\xf6\x5f\x1b\x2b\x9f\x27\x0c\x61\x54\x0c\x47\x47\x30\xfb\x2f\x00\x00\xff\xff\x29\x19\x25\xcc\x7f\x08\x00\x00")
|
||||
var _complySoc2PoliciesAccessMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x55\xc1\x6e\x1b\x47\x0c\xbd\xeb\x2b\x08\xe4\xd2\x1a\x91\x5a\xa7\x40\x51\xe8\x96\xba\x05\xec\x02\x45\x0c\x45\x40\xce\xd4\x2c\x57\xcb\x68\x76\xb8\x20\x67\xa5\xca\xa7\xfe\x46\x7f\xaf\x5f\x52\x70\x66\x25\xcb\x6e\xec\xe4\xa4\xdd\x19\x91\x7c\x8f\xef\x91\x9b\xb0\xa7\x25\xbc\x0f\x81\xcc\xe0\x43\xda\x08\x6a\xc3\x69\x0b\x98\x1a\x58\x93\xf6\x9c\x30\xb3\x24\xb8\x97\xc8\xe1\x38\xc3\xa0\x92\x8e\xfd\x12\xde\x7f\x58\xdf\xcf\x0c\x33\x5b\xcb\x64\xcb\x19\xc0\xfa\xe3\x8d\xff\x00\xcc\xe1\xe6\xe6\xe7\xc5\xf5\xc5\xf3\xbb\x8b\xe7\x9f\x66\x3d\x7e\x16\x5d\xd1\x9e\x8d\x25\x95\xd0\x39\x34\x98\x69\x09\x7f\x8c\x09\xae\xe1\xdd\x8f\xd7\xbf\x94\x80\x20\x7d\x4f\x29\x2f\xe1\x2e\x71\x66\x8c\xd0\x48\x18\xfd\x64\x36\x9f\xcf\x67\x6f\xe0\x7e\xd4\x41\x8c\x0a\xd6\x8f\x41\x06\x9a\xcd\x70\x01\xeb\x8e\x60\x98\x6e\xa4\x85\xdc\xb1\xc1\x50\xd0\x03\x1b\x64\x81\x86\x5a\x4e\x04\x83\x4a\xa0\x66\x54\x2a\x87\x52\xa9\x97\x5c\xd2\xb6\xf5\x65\x34\xd2\x72\x9b\x29\x74\x89\x03\x46\xe0\xd4\x2a\x5a\xd6\x31\xe4\x51\x09\x38\x01\x42\x8f\x29\x91\x42\xee\x30\x43\xcf\x89\x7b\x7e\xf0\xa4\x1d\x81\xb2\xed\x1c\x04\xa7\x56\xb4\xaf\x9d\x8c\x62\x06\xa2\x40\x7f\x0d\x62\xa3\xd2\x02\x26\xd8\x8f\x38\x71\x18\x22\x57\x5c\x18\xe3\xcb\xd5\x0f\x9c\x3b\x4e\xa5\x92\xe8\x16\x13\x3f\x94\x12\x5f\xcf\xd8\x8e\x31\xce\x33\xf7\xb5\x77\x03\x6a\xae\x6f\xd4\x0f\x51\x8e\x44\x56\xce\x83\xa4\xac\x18\xb2\xa8\x79\xca\x37\xf0\x2b\x86\xdd\x56\x65\x4c\x4d\x29\x70\x97\x40\xb4\x71\xe6\x72\xe6\xfd\xcd\xb4\xe1\xbb\x56\xa5\x87\x8d\xe4\x0e\x38\x19\x37\x15\x8b\x8c\xb9\x3c\x3f\xe7\xf4\xfd\xdb\xff\x1d\xb9\x9c\x4a\x91\x31\x65\x90\xda\x85\x41\x39\x05\x1e\x62\x51\x3e\x12\x5a\xf6\xa3\x3d\x47\xda\xd2\xc2\x5d\x2e\x63\xca\x10\x94\x6a\x82\x42\xde\x4d\x6e\x56\x20\xd2\x9e\xa2\x01\x2a\x81\x92\x65\xe5\x90\xa9\xa9\xe6\x88\xc7\x4a\x8c\x4c\x46\x0d\xde\x9f\x8d\x49\x1c\x33\xc5\x23\x24\xa2\xa6\xfe\x6f\x20\x75\xc2\x40\x18\x3a\x7f\x31\x49\xff\xfe\xfd\x8f\xc1\x67\xd9\x40\x33\x66\x26\x5b\xc0\xa7\x8e\xdc\x33\x6e\xad\x72\xa7\x12\x5f\x14\x12\x42\x87\x69\x4b\xe6\xdc\x8b\xd1\x2b\x01\x7b\x05\x78\x8d\x68\x7e\x50\xda\xcb\xae\xa2\x6a\x39\x97\xcc\x89\x0e\xb5\x9a\x47\x37\x6c\xb8\x89\xd4\xc0\xc1\xf1\xf8\xb5\x23\xf2\x9e\xed\x27\xef\x3e\x01\x82\x31\xcb\x96\x72\x47\x5a\x9d\x30\xad\x03\x77\xc1\xd5\x6f\xa3\xfa\xc6\x90\xf3\xf2\x58\x5e\xcd\xca\xfc\xf2\x02\x6e\xb9\xdc\xfd\x89\x09\xb7\xa4\x93\x21\x0c\x6e\x57\x30\x0e\x92\xa0\x63\x2d\x52\x61\x01\x77\x72\xdf\xe2\x31\x7c\x05\xd4\x23\x47\x83\xbb\xb5\x53\xa9\xf1\x0e\xaf\x7f\x0c\x2b\x49\x9c\x53\xee\x88\xb5\x50\x74\x90\x53\x8a\xbb\x75\xd5\xdb\x35\x83\xd0\x51\xd8\x45\xb6\x5c\xa2\x5f\xef\xe6\x24\x6b\x2b\xd3\x64\x3f\xcb\xeb\x6b\x46\x0e\x3e\xf7\xd2\x56\xc1\x4f\xe6\x00\xa5\x3d\xd3\xa1\xe6\xc5\x61\x50\xf1\x96\xe2\x97\xcc\xe7\x7d\x9e\xa1\x99\x04\x46\xf7\xda\x23\x0a\x7b\x4a\xe1\x20\xba\xb3\x62\x93\xaa\xcd\x97\x0b\x67\x01\xa3\x0c\xe3\x70\x16\x74\x5a\x05\x67\x8d\xa6\xcd\xf6\xaa\x48\x49\x32\xfb\x52\xf7\xee\x17\x77\x60\x3a\x4b\x03\x1d\x1a\x6c\xc8\x2d\x33\x7d\x1c\xa8\xb9\x40\x7a\xbb\x02\xa3\xd4\x78\xab\x0f\x44\xbb\x78\xac\xf2\x81\xd2\x20\x9a\x1d\xdf\xdd\x1a\x6c\xec\x7b\x54\x7e\xf0\x9a\x27\x2d\xa6\x4d\x7b\xce\x59\xba\xc3\xa9\xae\xba\x93\xfa\x93\x67\x27\x9d\xb1\x7c\xb3\x9e\xb6\xe9\x9c\xc0\xa6\xeb\xd3\x64\xb5\xbc\x27\xd8\x8c\xc6\xc9\x0f\x1b\x3c\x1a\x94\xf5\xa3\x14\x88\x87\x02\xa1\xd2\x0e\x97\x1b\xf4\xea\xd3\x73\xfa\xd3\x40\x16\x33\xd8\x4b\x63\xfb\x72\x6b\x0f\x1c\xe3\xc9\xc4\xb7\xab\x6a\xe1\x9a\xd2\xbf\x24\xc5\x61\x25\xf2\xa2\x9f\xde\x08\x37\x80\x47\xb6\x12\xa3\x1c\x4a\x3d\xc3\x9e\xc0\x32\x0d\x06\x68\xbe\x35\x23\x27\xf2\x96\x55\x34\x4f\x3f\xe4\x17\xb2\x5f\x7c\xf6\x4e\x24\x57\xc5\xae\xaf\x4c\x84\x5d\x10\xfa\xdd\x0d\xd7\x4b\xca\xdd\x5b\x87\xe5\x7f\x74\x9b\x38\xba\x6a\xfb\xaf\x8d\x95\xcf\x13\x86\x30\x2a\x86\xa3\x23\x98\xfd\x17\x00\x00\xff\xff\x61\xc4\x99\x8a\x82\x08\x00\x00")
|
||||
|
||||
func complySoc2PoliciesAccessMdBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
@@ -497,7 +497,7 @@ func complySoc2PoliciesAccessMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/access.md", size: 2175, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/access.md", size: 2178, mode: os.FileMode(420), modTime: time.Unix(1545087106, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -517,7 +517,7 @@ func complySoc2PoliciesApplicationMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/application.md", size: 8377, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/application.md", size: 8377, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -537,7 +537,7 @@ func complySoc2PoliciesAvailabilityMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/availability.md", size: 7019, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/availability.md", size: 7019, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -557,7 +557,7 @@ func complySoc2PoliciesChangeMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/change.md", size: 2793, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/change.md", size: 2793, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -577,7 +577,7 @@ func complySoc2PoliciesClassificationMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/classification.md", size: 14376, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/classification.md", size: 14376, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -597,7 +597,7 @@ func complySoc2PoliciesConductMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/conduct.md", size: 4492, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/conduct.md", size: 4492, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -617,7 +617,7 @@ func complySoc2PoliciesConfidentialityMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/confidentiality.md", size: 3653, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/confidentiality.md", size: 3653, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -637,7 +637,7 @@ func complySoc2PoliciesContinuityMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/continuity.md", size: 5043, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/continuity.md", size: 5043, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -657,7 +657,7 @@ func complySoc2PoliciesCyberMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/cyber.md", size: 4805, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/cyber.md", size: 4805, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -677,7 +677,7 @@ func complySoc2PoliciesDatacenterMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/datacenter.md", size: 3014, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/datacenter.md", size: 3014, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -697,7 +697,7 @@ func complySoc2PoliciesDevelopmentMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/development.md", size: 8933, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/development.md", size: 8933, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -717,7 +717,7 @@ func complySoc2PoliciesDisasterMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/disaster.md", size: 10315, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/disaster.md", size: 10315, mode: os.FileMode(420), modTime: time.Unix(1545087106, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -737,7 +737,7 @@ func complySoc2PoliciesEncryptionMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/encryption.md", size: 5381, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/encryption.md", size: 5381, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -757,7 +757,7 @@ func complySoc2PoliciesIncidentMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/incident.md", size: 8552, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/incident.md", size: 8552, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -777,7 +777,7 @@ func complySoc2PoliciesInformationMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/information.md", size: 5359, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/information.md", size: 5359, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -797,7 +797,7 @@ func complySoc2PoliciesLogMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/log.md", size: 4307, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/log.md", size: 4307, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -817,7 +817,7 @@ func complySoc2PoliciesMediaMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/media.md", size: 8819, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/media.md", size: 8819, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -837,7 +837,7 @@ func complySoc2PoliciesOfficeMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/office.md", size: 3927, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/office.md", size: 3927, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -857,7 +857,7 @@ func complySoc2PoliciesPasswordMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/password.md", size: 1796, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/password.md", size: 1796, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -877,7 +877,7 @@ func complySoc2PoliciesPolicyMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/policy.md", size: 892, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/policy.md", size: 892, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -897,7 +897,7 @@ func complySoc2PoliciesPrivacyMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/privacy.md", size: 346, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/privacy.md", size: 346, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -917,7 +917,7 @@ func complySoc2PoliciesProcessingMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/processing.md", size: 210, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/processing.md", size: 210, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -937,7 +937,7 @@ func complySoc2PoliciesRemoteMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/remote.md", size: 4119, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/remote.md", size: 4119, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -957,7 +957,7 @@ func complySoc2PoliciesRetentionMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/retention.md", size: 6811, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/retention.md", size: 6811, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -977,7 +977,7 @@ func complySoc2PoliciesRiskMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/risk.md", size: 10486, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/risk.md", size: 10486, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -997,7 +997,7 @@ func complySoc2PoliciesVendorMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/vendor.md", size: 3139, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/vendor.md", size: 3139, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1017,7 +1017,7 @@ func complySoc2PoliciesWorkstationMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/workstation.md", size: 1791, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/policies/workstation.md", size: 1791, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1037,7 +1037,7 @@ func complySoc2ProceduresReadmeMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/README.md", size: 92, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/README.md", size: 92, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1057,7 +1057,7 @@ func complySoc2ProceduresOffboardingMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/offboarding.md", size: 358, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/offboarding.md", size: 358, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1077,7 +1077,7 @@ func complySoc2ProceduresOnboardingMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/onboarding.md", size: 495, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/onboarding.md", size: 495, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1097,7 +1097,7 @@ func complySoc2ProceduresPatchMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/patch.md", size: 380, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/patch.md", size: 380, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1117,7 +1117,7 @@ func complySoc2ProceduresWorkstationMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/workstation.md", size: 1081, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/procedures/workstation.md", size: 1081, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1137,7 +1137,7 @@ func complySoc2StandardsReadmeMd() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/standards/README.md", size: 282, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/standards/README.md", size: 282, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1157,7 +1157,7 @@ func complySoc2StandardsTsc2017Yml() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/standards/TSC-2017.yml", size: 16305, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/standards/TSC-2017.yml", size: 16305, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1177,7 +1177,7 @@ func complySoc2TemplatesDefaultLatex() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/templates/default.latex", size: 7649, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/templates/default.latex", size: 7649, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -1197,7 +1197,7 @@ func complySoc2TemplatesIndexAce() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "comply-soc2/templates/index.ace", size: 7596, mode: os.FileMode(420), modTime: time.Unix(1532372226, 0)}
|
||||
info := bindataFileInfo{name: "comply-soc2/templates/index.ace", size: 7596, mode: os.FileMode(420), modTime: time.Unix(1545086630, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
@@ -17,6 +17,78 @@ majorRevisions:
|
||||
|
||||
# Control Environment Narrative
|
||||
|
||||
Here we narrate why our control environment satisfies the control keys listed in the YML block
|
||||
The following provides a description of the control structure of {{.Name}}.
|
||||
|
||||
# Template Coming Soon
|
||||
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,4 +9,39 @@ majorRevisions:
|
||||
|
||||
Here we describe the key products marketed by our organization
|
||||
|
||||
# Template Coming Soon
|
||||
# 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
|
||||
@@ -15,4 +15,99 @@ majorRevisions:
|
||||
|
||||
Here we narrate why our org satisfies the control keys listed in the YML block
|
||||
|
||||
# Template Coming Soon
|
||||
# {{.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
|
||||
|
||||
@@ -11,7 +11,7 @@ majorRevisions:
|
||||
---
|
||||
# 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. 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.
|
||||
|
||||
|
||||
10
tools.go
Normal file
10
tools.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// +build tools
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "github.com/Clever/gitsem"
|
||||
_ "github.com/aktau/github-release"
|
||||
_ "github.com/containous/go-bindata/go-bindata" // v1.0.0
|
||||
_ "github.com/elazarl/go-bindata-assetfs/go-bindata-assetfs" // v0.0.0-20170227122030-30f82fa23fd8
|
||||
)
|
||||
24
vendor/github.com/Clever/gitsem/.drone.yml
generated
vendored
Normal file
24
vendor/github.com/Clever/gitsem/.drone.yml
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
image: bradrydzewski/go:1.3
|
||||
script:
|
||||
- make test
|
||||
notify:
|
||||
email:
|
||||
recipients:
|
||||
- drone@clever.com
|
||||
hipchat:
|
||||
room: Clever-Dev-CI
|
||||
token: {{hipchat_token}}
|
||||
on_started: true
|
||||
on_success: true
|
||||
on_failure: true
|
||||
publish:
|
||||
github:
|
||||
branch: master
|
||||
script:
|
||||
- make release
|
||||
artifacts:
|
||||
- release
|
||||
tag: v$(cat VERSION)
|
||||
token: {{github_token}}
|
||||
user: Clever
|
||||
repo: gitsem
|
||||
25
vendor/github.com/Clever/gitsem/.gitignore
generated
vendored
Normal file
25
vendor/github.com/Clever/gitsem/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
|
||||
gitsem
|
||||
54
vendor/github.com/Clever/gitsem/Makefile
generated
vendored
Normal file
54
vendor/github.com/Clever/gitsem/Makefile
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
SHELL := /bin/bash
|
||||
PKG = github.com/Clever/gitsem
|
||||
PKGS = $(PKG)
|
||||
VERSION := $(shell cat VERSION)
|
||||
EXECUTABLE := gitsem
|
||||
BUILDS := \
|
||||
build/$(EXECUTABLE)-v$(VERSION)-darwin-amd64 \
|
||||
build/$(EXECUTABLE)-v$(VERSION)-linux-amd64 \
|
||||
build/$(EXECUTABLE)-v$(VERSION)-windows-amd64
|
||||
COMPRESSED_BUILDS := $(BUILDS:%=%.tar.gz)
|
||||
RELEASE_ARTIFACTS := $(COMPRESSED_BUILDS:build/%=release/%)
|
||||
|
||||
.PHONY: test golint
|
||||
|
||||
golint:
|
||||
@go get github.com/golang/lint/golint
|
||||
|
||||
test: $(PKGS)
|
||||
|
||||
$(PKGS): golint
|
||||
@go get -d -t $@
|
||||
@gofmt -w=true $(GOPATH)/src/$@*/**.go
|
||||
ifneq ($(NOLINT),1)
|
||||
@echo "LINTING..."
|
||||
@PATH=$(PATH):$(GOPATH)/bin golint $(GOPATH)/src/$@*/**.go
|
||||
@echo ""
|
||||
endif
|
||||
ifeq ($(COVERAGE),1)
|
||||
@go test -cover -coverprofile=$(GOPATH)/src/$@/c.out $@ -test.v
|
||||
@go tool cover -html=$(GOPATH)/src/$@/c.out
|
||||
else
|
||||
@echo "TESTING..."
|
||||
@go test $@ -test.v
|
||||
endif
|
||||
|
||||
run:
|
||||
@go run main.go
|
||||
|
||||
build/$(EXECUTABLE)-v$(VERSION)-darwin-amd64:
|
||||
GOARCH=amd64 GOOS=darwin go build -o "$@/$(EXECUTABLE)"
|
||||
build/$(EXECUTABLE)-v$(VERSION)-linux-amd64:
|
||||
GOARCH=amd64 GOOS=linux go build -o "$@/$(EXECUTABLE)"
|
||||
build/$(EXECUTABLE)-v$(VERSION)-windows-amd64:
|
||||
GOARCH=amd64 GOOS=windows go build -o "$@/$(EXECUTABLE).exe"
|
||||
build: $(BUILDS)
|
||||
%.tar.gz: %
|
||||
tar -C `dirname $<` -zcvf "$<.tar.gz" `basename $<`
|
||||
$(RELEASE_ARTIFACTS): release/% : build/%
|
||||
mkdir -p release
|
||||
cp $< $@
|
||||
release: $(RELEASE_ARTIFACTS)
|
||||
|
||||
clean:
|
||||
rm -rf build release
|
||||
34
vendor/github.com/Clever/gitsem/README.md
generated
vendored
Normal file
34
vendor/github.com/Clever/gitsem/README.md
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# gitsem
|
||||
|
||||
A command line utility for managing semantically versioned (semver) git tags.
|
||||
|
||||
Run this in a git repository to bump the version and write the new data back to the VERSION file.
|
||||
It will also create a version commit and (optional) tag, and fail if the repo is not clean.
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
$ go get github.com/Clever/gitsem
|
||||
```
|
||||
|
||||
## Example
|
||||
```shell
|
||||
$ gitsem patch
|
||||
$ gitsem -m "Upgrade to %s for reasons" patch
|
||||
$ gitsem minor
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```shell
|
||||
gitsem [options] version
|
||||
```
|
||||
|
||||
`version` can be one of: `newversion | patch | minor | major`
|
||||
|
||||
The version argument should be a valid semver string, or a field of a semver string (one of "patch", "minor", or "major").
|
||||
In the second case, the existing version will be incremented by 1 in the specified field.
|
||||
|
||||
### Options
|
||||
- `m=%s` specifies a commit message to use when bumping the version. If %s appears, it will be replaced with the new version number.
|
||||
- `tag=true` whether or not to create a tag at the version commit
|
||||
1
vendor/github.com/Clever/gitsem/VERSION
generated
vendored
Normal file
1
vendor/github.com/Clever/gitsem/VERSION
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1.0.4
|
||||
39
vendor/github.com/Clever/gitsem/git.go
generated
vendored
Normal file
39
vendor/github.com/Clever/gitsem/git.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func isRepoClean() (bool, error) {
|
||||
cmd := exec.Command("git", "status", "-s")
|
||||
result := &bytes.Buffer{}
|
||||
cmd.Stdout = result
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return result.String() == "", nil
|
||||
}
|
||||
|
||||
func repoRoot() (string, error) {
|
||||
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
|
||||
result := &bytes.Buffer{}
|
||||
cmd.Stdout = result
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(result.String()), nil
|
||||
}
|
||||
|
||||
func addFile(path string) error {
|
||||
return exec.Command("git", "add", path).Run()
|
||||
}
|
||||
|
||||
func commit(message string) error {
|
||||
return exec.Command("git", "commit", "-m", message).Run()
|
||||
}
|
||||
|
||||
func tag(version string) error {
|
||||
return exec.Command("git", "tag", version).Run()
|
||||
}
|
||||
126
vendor/github.com/Clever/gitsem/main.go
generated
vendored
Normal file
126
vendor/github.com/Clever/gitsem/main.go
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"gopkg.in/blang/semver.v1"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func commitMessage(message, version string) string {
|
||||
if strings.Contains(message, "%s") {
|
||||
return fmt.Sprintf(message, version)
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
func getCurrentVersion(path string) (*semver.Version, error) {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return &semver.Version{}, nil
|
||||
}
|
||||
contents, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return semver.New(strings.TrimSpace(string(contents)))
|
||||
}
|
||||
|
||||
const versionFileName = "VERSION"
|
||||
|
||||
func exitWithError(message string) {
|
||||
fmt.Fprintf(os.Stderr, message+"\n\n")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func bump(old *semver.Version, part string) *semver.Version {
|
||||
// We don't want to mutate the input, but there's no Clone or Copy method on a semver.Version,
|
||||
// so we make a new one by parsing the string version of the old one.
|
||||
// We ignore any errors because we know it's valid semver.
|
||||
new, _ := semver.New(old.String())
|
||||
switch part {
|
||||
case "major":
|
||||
new.Major++
|
||||
new.Minor = 0
|
||||
new.Patch = 0
|
||||
case "minor":
|
||||
new.Minor++
|
||||
new.Patch = 0
|
||||
case "patch":
|
||||
new.Patch++
|
||||
}
|
||||
return new
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage of %s: [options] version\n\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, "version can be one of: newversion | patch | minor | major\n\n")
|
||||
fmt.Fprintf(os.Stderr, "options:\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
message := flag.String("m", "%s", "commit message for version commit")
|
||||
help := flag.Bool("h", false, "print usage and exit")
|
||||
shouldTag := flag.Bool("tag", true, "whether or not to make a tag at the version commit")
|
||||
flag.Parse()
|
||||
|
||||
if *help {
|
||||
flag.Usage()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if *message == "" {
|
||||
exitWithError("missing message")
|
||||
}
|
||||
|
||||
if clean, err := isRepoClean(); err != nil {
|
||||
log.Fatal(err)
|
||||
} else if !clean {
|
||||
log.Fatal("repo isn't clean")
|
||||
}
|
||||
|
||||
root, err := repoRoot()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
versionFile := filepath.Join(root, versionFileName)
|
||||
version, err := getCurrentVersion(versionFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if len(flag.Args()) != 1 {
|
||||
exitWithError("gitsem takes exactly one non-flag argument: version")
|
||||
}
|
||||
|
||||
newVersion := flag.Args()[0]
|
||||
switch newVersion {
|
||||
case "patch", "minor", "major":
|
||||
version = bump(version, newVersion)
|
||||
default:
|
||||
if version, err = semver.New(newVersion); err != nil {
|
||||
log.Fatalf("failed to parse %s as semver: %s", newVersion, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(versionFile, []byte(version.String()), 0666); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := addFile(versionFile); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
versionString := "v" + version.String()
|
||||
*message = commitMessage(*message, versionString)
|
||||
if err := commit(*message); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if *shouldTag {
|
||||
if err := tag(versionString); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
fmt.Println(versionString)
|
||||
}
|
||||
274
vendor/github.com/Microsoft/go-winio/ea.go
generated
vendored
274
vendor/github.com/Microsoft/go-winio/ea.go
generated
vendored
@@ -1,137 +1,137 @@
|
||||
package winio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type fileFullEaInformation struct {
|
||||
NextEntryOffset uint32
|
||||
Flags uint8
|
||||
NameLength uint8
|
||||
ValueLength uint16
|
||||
}
|
||||
|
||||
var (
|
||||
fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
|
||||
|
||||
errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
|
||||
errEaNameTooLarge = errors.New("extended attribute name too large")
|
||||
errEaValueTooLarge = errors.New("extended attribute value too large")
|
||||
)
|
||||
|
||||
// ExtendedAttribute represents a single Windows EA.
|
||||
type ExtendedAttribute struct {
|
||||
Name string
|
||||
Value []byte
|
||||
Flags uint8
|
||||
}
|
||||
|
||||
func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
|
||||
var info fileFullEaInformation
|
||||
err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
|
||||
if err != nil {
|
||||
err = errInvalidEaBuffer
|
||||
return
|
||||
}
|
||||
|
||||
nameOffset := fileFullEaInformationSize
|
||||
nameLen := int(info.NameLength)
|
||||
valueOffset := nameOffset + int(info.NameLength) + 1
|
||||
valueLen := int(info.ValueLength)
|
||||
nextOffset := int(info.NextEntryOffset)
|
||||
if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
|
||||
err = errInvalidEaBuffer
|
||||
return
|
||||
}
|
||||
|
||||
ea.Name = string(b[nameOffset : nameOffset+nameLen])
|
||||
ea.Value = b[valueOffset : valueOffset+valueLen]
|
||||
ea.Flags = info.Flags
|
||||
if info.NextEntryOffset != 0 {
|
||||
nb = b[info.NextEntryOffset:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
|
||||
// buffer retrieved from BackupRead, ZwQueryEaFile, etc.
|
||||
func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
|
||||
for len(b) != 0 {
|
||||
ea, nb, err := parseEa(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
eas = append(eas, ea)
|
||||
b = nb
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
|
||||
if int(uint8(len(ea.Name))) != len(ea.Name) {
|
||||
return errEaNameTooLarge
|
||||
}
|
||||
if int(uint16(len(ea.Value))) != len(ea.Value) {
|
||||
return errEaValueTooLarge
|
||||
}
|
||||
entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value))
|
||||
withPadding := (entrySize + 3) &^ 3
|
||||
nextOffset := uint32(0)
|
||||
if !last {
|
||||
nextOffset = withPadding
|
||||
}
|
||||
info := fileFullEaInformation{
|
||||
NextEntryOffset: nextOffset,
|
||||
Flags: ea.Flags,
|
||||
NameLength: uint8(len(ea.Name)),
|
||||
ValueLength: uint16(len(ea.Value)),
|
||||
}
|
||||
|
||||
err := binary.Write(buf, binary.LittleEndian, &info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Write([]byte(ea.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = buf.WriteByte(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Write(ea.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION
|
||||
// buffer for use with BackupWrite, ZwSetEaFile, etc.
|
||||
func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
for i := range eas {
|
||||
last := false
|
||||
if i == len(eas)-1 {
|
||||
last = true
|
||||
}
|
||||
|
||||
err := writeEa(&buf, &eas[i], last)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
package winio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type fileFullEaInformation struct {
|
||||
NextEntryOffset uint32
|
||||
Flags uint8
|
||||
NameLength uint8
|
||||
ValueLength uint16
|
||||
}
|
||||
|
||||
var (
|
||||
fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
|
||||
|
||||
errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
|
||||
errEaNameTooLarge = errors.New("extended attribute name too large")
|
||||
errEaValueTooLarge = errors.New("extended attribute value too large")
|
||||
)
|
||||
|
||||
// ExtendedAttribute represents a single Windows EA.
|
||||
type ExtendedAttribute struct {
|
||||
Name string
|
||||
Value []byte
|
||||
Flags uint8
|
||||
}
|
||||
|
||||
func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
|
||||
var info fileFullEaInformation
|
||||
err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
|
||||
if err != nil {
|
||||
err = errInvalidEaBuffer
|
||||
return
|
||||
}
|
||||
|
||||
nameOffset := fileFullEaInformationSize
|
||||
nameLen := int(info.NameLength)
|
||||
valueOffset := nameOffset + int(info.NameLength) + 1
|
||||
valueLen := int(info.ValueLength)
|
||||
nextOffset := int(info.NextEntryOffset)
|
||||
if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
|
||||
err = errInvalidEaBuffer
|
||||
return
|
||||
}
|
||||
|
||||
ea.Name = string(b[nameOffset : nameOffset+nameLen])
|
||||
ea.Value = b[valueOffset : valueOffset+valueLen]
|
||||
ea.Flags = info.Flags
|
||||
if info.NextEntryOffset != 0 {
|
||||
nb = b[info.NextEntryOffset:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
|
||||
// buffer retrieved from BackupRead, ZwQueryEaFile, etc.
|
||||
func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
|
||||
for len(b) != 0 {
|
||||
ea, nb, err := parseEa(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
eas = append(eas, ea)
|
||||
b = nb
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
|
||||
if int(uint8(len(ea.Name))) != len(ea.Name) {
|
||||
return errEaNameTooLarge
|
||||
}
|
||||
if int(uint16(len(ea.Value))) != len(ea.Value) {
|
||||
return errEaValueTooLarge
|
||||
}
|
||||
entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value))
|
||||
withPadding := (entrySize + 3) &^ 3
|
||||
nextOffset := uint32(0)
|
||||
if !last {
|
||||
nextOffset = withPadding
|
||||
}
|
||||
info := fileFullEaInformation{
|
||||
NextEntryOffset: nextOffset,
|
||||
Flags: ea.Flags,
|
||||
NameLength: uint8(len(ea.Name)),
|
||||
ValueLength: uint16(len(ea.Value)),
|
||||
}
|
||||
|
||||
err := binary.Write(buf, binary.LittleEndian, &info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Write([]byte(ea.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = buf.WriteByte(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Write(ea.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION
|
||||
// buffer for use with BackupWrite, ZwSetEaFile, etc.
|
||||
func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
for i := range eas {
|
||||
last := false
|
||||
if i == len(eas)-1 {
|
||||
last = true
|
||||
}
|
||||
|
||||
err := writeEa(&buf, &eas[i], last)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
18
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
18
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
@@ -16,6 +16,7 @@ import (
|
||||
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
|
||||
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
|
||||
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
|
||||
//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
|
||||
|
||||
type atomicBool int32
|
||||
|
||||
@@ -79,6 +80,7 @@ type win32File struct {
|
||||
wg sync.WaitGroup
|
||||
wgLock sync.RWMutex
|
||||
closing atomicBool
|
||||
socket bool
|
||||
readDeadline deadlineHandler
|
||||
writeDeadline deadlineHandler
|
||||
}
|
||||
@@ -109,7 +111,13 @@ func makeWin32File(h syscall.Handle) (*win32File, error) {
|
||||
}
|
||||
|
||||
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
|
||||
return makeWin32File(h)
|
||||
// If we return the result of makeWin32File directly, it can result in an
|
||||
// interface-wrapped nil, rather than a nil interface value.
|
||||
f, err := makeWin32File(h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// closeHandle closes the resources associated with a Win32 handle
|
||||
@@ -190,6 +198,10 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
||||
if f.closing.isSet() {
|
||||
err = ErrFileClosed
|
||||
}
|
||||
} else if err != nil && f.socket {
|
||||
// err is from Win32. Query the overlapped structure to get the winsock error.
|
||||
var bytes, flags uint32
|
||||
err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
|
||||
}
|
||||
case <-timeout:
|
||||
cancelIoEx(f.handle, &c.o)
|
||||
@@ -265,6 +277,10 @@ func (f *win32File) Flush() error {
|
||||
return syscall.FlushFileBuffers(f.handle)
|
||||
}
|
||||
|
||||
func (f *win32File) Fd() uintptr {
|
||||
return uintptr(f.handle)
|
||||
}
|
||||
|
||||
func (d *deadlineHandler) set(deadline time.Time) error {
|
||||
d.setLock.Lock()
|
||||
defer d.setLock.Unlock()
|
||||
|
||||
3
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
3
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
@@ -20,7 +20,8 @@ const (
|
||||
// FileBasicInfo contains file access time and file attributes information.
|
||||
type FileBasicInfo struct {
|
||||
CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
|
||||
FileAttributes uintptr // includes padding
|
||||
FileAttributes uint32
|
||||
pad uint32 // padding
|
||||
}
|
||||
|
||||
// GetFileBasicInfo retrieves times and attributes for a file.
|
||||
|
||||
9
vendor/github.com/Microsoft/go-winio/go.mod
generated
vendored
Normal file
9
vendor/github.com/Microsoft/go-winio/go.mod
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module github.com/Microsoft/go-winio
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/sirupsen/logrus v1.4.1
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b
|
||||
)
|
||||
16
vendor/github.com/Microsoft/go-winio/go.sum
generated
vendored
Normal file
16
vendor/github.com/Microsoft/go-winio/go.sum
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
305
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
Normal file
305
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
package winio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Microsoft/go-winio/pkg/guid"
|
||||
)
|
||||
|
||||
//sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
|
||||
|
||||
const (
|
||||
afHvSock = 34 // AF_HYPERV
|
||||
|
||||
socketError = ^uintptr(0)
|
||||
)
|
||||
|
||||
// An HvsockAddr is an address for a AF_HYPERV socket.
|
||||
type HvsockAddr struct {
|
||||
VMID guid.GUID
|
||||
ServiceID guid.GUID
|
||||
}
|
||||
|
||||
type rawHvsockAddr struct {
|
||||
Family uint16
|
||||
_ uint16
|
||||
VMID guid.GUID
|
||||
ServiceID guid.GUID
|
||||
}
|
||||
|
||||
// Network returns the address's network name, "hvsock".
|
||||
func (addr *HvsockAddr) Network() string {
|
||||
return "hvsock"
|
||||
}
|
||||
|
||||
func (addr *HvsockAddr) String() string {
|
||||
return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID)
|
||||
}
|
||||
|
||||
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
|
||||
func VsockServiceID(port uint32) guid.GUID {
|
||||
g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
|
||||
g.Data1 = port
|
||||
return g
|
||||
}
|
||||
|
||||
func (addr *HvsockAddr) raw() rawHvsockAddr {
|
||||
return rawHvsockAddr{
|
||||
Family: afHvSock,
|
||||
VMID: addr.VMID,
|
||||
ServiceID: addr.ServiceID,
|
||||
}
|
||||
}
|
||||
|
||||
func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
|
||||
addr.VMID = raw.VMID
|
||||
addr.ServiceID = raw.ServiceID
|
||||
}
|
||||
|
||||
// HvsockListener is a socket listener for the AF_HYPERV address family.
|
||||
type HvsockListener struct {
|
||||
sock *win32File
|
||||
addr HvsockAddr
|
||||
}
|
||||
|
||||
// HvsockConn is a connected socket of the AF_HYPERV address family.
|
||||
type HvsockConn struct {
|
||||
sock *win32File
|
||||
local, remote HvsockAddr
|
||||
}
|
||||
|
||||
func newHvSocket() (*win32File, error) {
|
||||
fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
|
||||
if err != nil {
|
||||
return nil, os.NewSyscallError("socket", err)
|
||||
}
|
||||
f, err := makeWin32File(fd)
|
||||
if err != nil {
|
||||
syscall.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
f.socket = true
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// ListenHvsock listens for connections on the specified hvsock address.
|
||||
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
|
||||
l := &HvsockListener{addr: *addr}
|
||||
sock, err := newHvSocket()
|
||||
if err != nil {
|
||||
return nil, l.opErr("listen", err)
|
||||
}
|
||||
sa := addr.raw()
|
||||
err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa)))
|
||||
if err != nil {
|
||||
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
|
||||
}
|
||||
err = syscall.Listen(sock.handle, 16)
|
||||
if err != nil {
|
||||
return nil, l.opErr("listen", os.NewSyscallError("listen", err))
|
||||
}
|
||||
return &HvsockListener{sock: sock, addr: *addr}, nil
|
||||
}
|
||||
|
||||
func (l *HvsockListener) opErr(op string, err error) error {
|
||||
return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err}
|
||||
}
|
||||
|
||||
// Addr returns the listener's network address.
|
||||
func (l *HvsockListener) Addr() net.Addr {
|
||||
return &l.addr
|
||||
}
|
||||
|
||||
// Accept waits for the next connection and returns it.
|
||||
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
|
||||
sock, err := newHvSocket()
|
||||
if err != nil {
|
||||
return nil, l.opErr("accept", err)
|
||||
}
|
||||
defer func() {
|
||||
if sock != nil {
|
||||
sock.Close()
|
||||
}
|
||||
}()
|
||||
c, err := l.sock.prepareIo()
|
||||
if err != nil {
|
||||
return nil, l.opErr("accept", err)
|
||||
}
|
||||
defer l.sock.wg.Done()
|
||||
|
||||
// AcceptEx, per documentation, requires an extra 16 bytes per address.
|
||||
const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
|
||||
var addrbuf [addrlen * 2]byte
|
||||
|
||||
var bytes uint32
|
||||
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
|
||||
_, err = l.sock.asyncIo(c, nil, bytes, err)
|
||||
if err != nil {
|
||||
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
|
||||
}
|
||||
conn := &HvsockConn{
|
||||
sock: sock,
|
||||
}
|
||||
conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
|
||||
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
|
||||
sock = nil
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Close closes the listener, causing any pending Accept calls to fail.
|
||||
func (l *HvsockListener) Close() error {
|
||||
return l.sock.Close()
|
||||
}
|
||||
|
||||
/* Need to finish ConnectEx handling
|
||||
func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
|
||||
sock, err := newHvSocket()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if sock != nil {
|
||||
sock.Close()
|
||||
}
|
||||
}()
|
||||
c, err := sock.prepareIo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer sock.wg.Done()
|
||||
var bytes uint32
|
||||
err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
|
||||
_, err = sock.asyncIo(ctx, c, nil, bytes, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn := &HvsockConn{
|
||||
sock: sock,
|
||||
remote: *addr,
|
||||
}
|
||||
sock = nil
|
||||
return conn, nil
|
||||
}
|
||||
*/
|
||||
|
||||
func (conn *HvsockConn) opErr(op string, err error) error {
|
||||
return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
|
||||
}
|
||||
|
||||
func (conn *HvsockConn) Read(b []byte) (int, error) {
|
||||
c, err := conn.sock.prepareIo()
|
||||
if err != nil {
|
||||
return 0, conn.opErr("read", err)
|
||||
}
|
||||
defer conn.sock.wg.Done()
|
||||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||
var flags, bytes uint32
|
||||
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
|
||||
n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
|
||||
if err != nil {
|
||||
if _, ok := err.(syscall.Errno); ok {
|
||||
err = os.NewSyscallError("wsarecv", err)
|
||||
}
|
||||
return 0, conn.opErr("read", err)
|
||||
} else if n == 0 {
|
||||
err = io.EOF
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (conn *HvsockConn) Write(b []byte) (int, error) {
|
||||
t := 0
|
||||
for len(b) != 0 {
|
||||
n, err := conn.write(b)
|
||||
if err != nil {
|
||||
return t + n, err
|
||||
}
|
||||
t += n
|
||||
b = b[n:]
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (conn *HvsockConn) write(b []byte) (int, error) {
|
||||
c, err := conn.sock.prepareIo()
|
||||
if err != nil {
|
||||
return 0, conn.opErr("write", err)
|
||||
}
|
||||
defer conn.sock.wg.Done()
|
||||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||
var bytes uint32
|
||||
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
|
||||
n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
|
||||
if err != nil {
|
||||
if _, ok := err.(syscall.Errno); ok {
|
||||
err = os.NewSyscallError("wsasend", err)
|
||||
}
|
||||
return 0, conn.opErr("write", err)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Close closes the socket connection, failing any pending read or write calls.
|
||||
func (conn *HvsockConn) Close() error {
|
||||
return conn.sock.Close()
|
||||
}
|
||||
|
||||
func (conn *HvsockConn) shutdown(how int) error {
|
||||
err := syscall.Shutdown(conn.sock.handle, syscall.SHUT_RD)
|
||||
if err != nil {
|
||||
return os.NewSyscallError("shutdown", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseRead shuts down the read end of the socket.
|
||||
func (conn *HvsockConn) CloseRead() error {
|
||||
err := conn.shutdown(syscall.SHUT_RD)
|
||||
if err != nil {
|
||||
return conn.opErr("close", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseWrite shuts down the write end of the socket, notifying the other endpoint that
|
||||
// no more data will be written.
|
||||
func (conn *HvsockConn) CloseWrite() error {
|
||||
err := conn.shutdown(syscall.SHUT_WR)
|
||||
if err != nil {
|
||||
return conn.opErr("close", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalAddr returns the local address of the connection.
|
||||
func (conn *HvsockConn) LocalAddr() net.Addr {
|
||||
return &conn.local
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote address of the connection.
|
||||
func (conn *HvsockConn) RemoteAddr() net.Addr {
|
||||
return &conn.remote
|
||||
}
|
||||
|
||||
// SetDeadline implements the net.Conn SetDeadline method.
|
||||
func (conn *HvsockConn) SetDeadline(t time.Time) error {
|
||||
conn.SetReadDeadline(t)
|
||||
conn.SetWriteDeadline(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetReadDeadline implements the net.Conn SetReadDeadline method.
|
||||
func (conn *HvsockConn) SetReadDeadline(t time.Time) error {
|
||||
return conn.sock.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
|
||||
func (conn *HvsockConn) SetWriteDeadline(t time.Time) error {
|
||||
return conn.sock.SetWriteDeadline(t)
|
||||
}
|
||||
266
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
266
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
@@ -3,10 +3,13 @@
|
||||
package winio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
@@ -15,10 +18,51 @@ import (
|
||||
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
|
||||
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
|
||||
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
|
||||
//sys waitNamedPipe(name string, timeout uint32) (err error) = WaitNamedPipeW
|
||||
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
|
||||
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
|
||||
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
|
||||
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile
|
||||
//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
|
||||
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U
|
||||
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl
|
||||
|
||||
type ioStatusBlock struct {
|
||||
Status, Information uintptr
|
||||
}
|
||||
|
||||
type objectAttributes struct {
|
||||
Length uintptr
|
||||
RootDirectory uintptr
|
||||
ObjectName *unicodeString
|
||||
Attributes uintptr
|
||||
SecurityDescriptor *securityDescriptor
|
||||
SecurityQoS uintptr
|
||||
}
|
||||
|
||||
type unicodeString struct {
|
||||
Length uint16
|
||||
MaximumLength uint16
|
||||
Buffer uintptr
|
||||
}
|
||||
|
||||
type securityDescriptor struct {
|
||||
Revision byte
|
||||
Sbz1 byte
|
||||
Control uint16
|
||||
Owner uintptr
|
||||
Group uintptr
|
||||
Sacl uintptr
|
||||
Dacl uintptr
|
||||
}
|
||||
|
||||
type ntstatus int32
|
||||
|
||||
func (status ntstatus) Err() error {
|
||||
if status >= 0 {
|
||||
return nil
|
||||
}
|
||||
return rtlNtStatusToDosError(status)
|
||||
}
|
||||
|
||||
const (
|
||||
cERROR_PIPE_BUSY = syscall.Errno(231)
|
||||
@@ -26,21 +70,20 @@ const (
|
||||
cERROR_PIPE_CONNECTED = syscall.Errno(535)
|
||||
cERROR_SEM_TIMEOUT = syscall.Errno(121)
|
||||
|
||||
cPIPE_ACCESS_DUPLEX = 0x3
|
||||
cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000
|
||||
cSECURITY_SQOS_PRESENT = 0x100000
|
||||
cSECURITY_ANONYMOUS = 0
|
||||
|
||||
cPIPE_REJECT_REMOTE_CLIENTS = 0x8
|
||||
|
||||
cPIPE_UNLIMITED_INSTANCES = 255
|
||||
|
||||
cNMPWAIT_USE_DEFAULT_WAIT = 0
|
||||
cNMPWAIT_NOWAIT = 1
|
||||
cSECURITY_SQOS_PRESENT = 0x100000
|
||||
cSECURITY_ANONYMOUS = 0
|
||||
|
||||
cPIPE_TYPE_MESSAGE = 4
|
||||
|
||||
cPIPE_READMODE_MESSAGE = 2
|
||||
|
||||
cFILE_OPEN = 1
|
||||
cFILE_CREATE = 2
|
||||
|
||||
cFILE_PIPE_MESSAGE_TYPE = 1
|
||||
cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2
|
||||
|
||||
cSE_DACL_PRESENT = 4
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -121,6 +164,11 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
|
||||
// zero-byte message, ensure that all future Read() calls
|
||||
// also return EOF.
|
||||
f.readEOF = true
|
||||
} else if err == syscall.ERROR_MORE_DATA {
|
||||
// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
|
||||
// and the message still has more bytes. Treat this as a success, since
|
||||
// this package presents all named pipes as byte streams.
|
||||
err = nil
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
@@ -133,40 +181,53 @@ func (s pipeAddress) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
|
||||
func tryDialPipe(ctx context.Context, path *string) (syscall.Handle, error) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return syscall.Handle(0), ctx.Err()
|
||||
default:
|
||||
h, err := createFile(*path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
||||
if err == nil {
|
||||
return h, nil
|
||||
}
|
||||
if err != cERROR_PIPE_BUSY {
|
||||
return h, &os.PathError{Err: err, Op: "open", Path: *path}
|
||||
}
|
||||
// Wait 10 msec and try again. This is a rather simplistic
|
||||
// view, as we always try each 10 milliseconds.
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DialPipe connects to a named pipe by path, timing out if the connection
|
||||
// takes longer than the specified duration. If timeout is nil, then the timeout
|
||||
// is the default timeout established by the pipe server.
|
||||
// takes longer than the specified duration. If timeout is nil, then we use
|
||||
// a default timeout of 2 seconds. (We do not use WaitNamedPipe.)
|
||||
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
|
||||
var absTimeout time.Time
|
||||
if timeout != nil {
|
||||
absTimeout = time.Now().Add(*timeout)
|
||||
} else {
|
||||
absTimeout = time.Now().Add(time.Second * 2)
|
||||
}
|
||||
ctx, _ := context.WithDeadline(context.Background(), absTimeout)
|
||||
conn, err := DialPipeContext(ctx, path)
|
||||
if err == context.DeadlineExceeded {
|
||||
return nil, ErrTimeout
|
||||
}
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// DialPipeContext attempts to connect to a named pipe by `path` until `ctx`
|
||||
// cancellation or timeout.
|
||||
func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
|
||||
var err error
|
||||
var h syscall.Handle
|
||||
for {
|
||||
h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
||||
if err != cERROR_PIPE_BUSY {
|
||||
break
|
||||
}
|
||||
now := time.Now()
|
||||
var ms uint32
|
||||
if absTimeout.IsZero() {
|
||||
ms = cNMPWAIT_USE_DEFAULT_WAIT
|
||||
} else if now.After(absTimeout) {
|
||||
ms = cNMPWAIT_NOWAIT
|
||||
} else {
|
||||
ms = uint32(absTimeout.Sub(now).Nanoseconds() / 1000 / 1000)
|
||||
}
|
||||
err = waitNamedPipe(path, ms)
|
||||
if err != nil {
|
||||
if err == cERROR_SEM_TIMEOUT {
|
||||
return nil, ErrTimeout
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
h, err = tryDialPipe(ctx, &path)
|
||||
if err != nil {
|
||||
return nil, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var flags uint32
|
||||
@@ -175,16 +236,6 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var state uint32
|
||||
err = getNamedPipeHandleState(h, &state, nil, nil, nil, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if state&cPIPE_READMODE_MESSAGE != 0 {
|
||||
return nil, &os.PathError{Op: "open", Path: path, Err: errors.New("message readmode pipes not supported")}
|
||||
}
|
||||
|
||||
f, err := makeWin32File(h)
|
||||
if err != nil {
|
||||
syscall.Close(h)
|
||||
@@ -207,43 +258,87 @@ type acceptResponse struct {
|
||||
}
|
||||
|
||||
type win32PipeListener struct {
|
||||
firstHandle syscall.Handle
|
||||
path string
|
||||
securityDescriptor []byte
|
||||
config PipeConfig
|
||||
acceptCh chan (chan acceptResponse)
|
||||
closeCh chan int
|
||||
doneCh chan int
|
||||
firstHandle syscall.Handle
|
||||
path string
|
||||
config PipeConfig
|
||||
acceptCh chan (chan acceptResponse)
|
||||
closeCh chan int
|
||||
doneCh chan int
|
||||
}
|
||||
|
||||
func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
|
||||
var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED
|
||||
if first {
|
||||
flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE
|
||||
}
|
||||
|
||||
var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS
|
||||
if c.MessageMode {
|
||||
mode |= cPIPE_TYPE_MESSAGE
|
||||
}
|
||||
|
||||
sa := &syscall.SecurityAttributes{}
|
||||
sa.Length = uint32(unsafe.Sizeof(*sa))
|
||||
if securityDescriptor != nil {
|
||||
len := uint32(len(securityDescriptor))
|
||||
sa.SecurityDescriptor = localAlloc(0, len)
|
||||
defer localFree(sa.SecurityDescriptor)
|
||||
copy((*[0xffff]byte)(unsafe.Pointer(sa.SecurityDescriptor))[:], securityDescriptor)
|
||||
}
|
||||
h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, sa)
|
||||
func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
|
||||
path16, err := syscall.UTF16FromString(path)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
|
||||
var oa objectAttributes
|
||||
oa.Length = unsafe.Sizeof(oa)
|
||||
|
||||
var ntPath unicodeString
|
||||
if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil {
|
||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
defer localFree(ntPath.Buffer)
|
||||
oa.ObjectName = &ntPath
|
||||
|
||||
// The security descriptor is only needed for the first pipe.
|
||||
if first {
|
||||
if sd != nil {
|
||||
len := uint32(len(sd))
|
||||
sdb := localAlloc(0, len)
|
||||
defer localFree(sdb)
|
||||
copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
|
||||
oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
|
||||
} else {
|
||||
// Construct the default named pipe security descriptor.
|
||||
var dacl uintptr
|
||||
if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
|
||||
return 0, fmt.Errorf("getting default named pipe ACL: %s", err)
|
||||
}
|
||||
defer localFree(dacl)
|
||||
|
||||
sdb := &securityDescriptor{
|
||||
Revision: 1,
|
||||
Control: cSE_DACL_PRESENT,
|
||||
Dacl: dacl,
|
||||
}
|
||||
oa.SecurityDescriptor = sdb
|
||||
}
|
||||
}
|
||||
|
||||
typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS)
|
||||
if c.MessageMode {
|
||||
typ |= cFILE_PIPE_MESSAGE_TYPE
|
||||
}
|
||||
|
||||
disposition := uint32(cFILE_OPEN)
|
||||
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
|
||||
if first {
|
||||
disposition = cFILE_CREATE
|
||||
// By not asking for read or write access, the named pipe file system
|
||||
// will put this pipe into an initially disconnected state, blocking
|
||||
// client connections until the next call with first == false.
|
||||
access = syscall.SYNCHRONIZE
|
||||
}
|
||||
|
||||
timeout := int64(-50 * 10000) // 50ms
|
||||
|
||||
var (
|
||||
h syscall.Handle
|
||||
iosb ioStatusBlock
|
||||
)
|
||||
err = ntCreateNamedPipeFile(&h, access, &oa, &iosb, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout).Err()
|
||||
if err != nil {
|
||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
|
||||
runtime.KeepAlive(ntPath)
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
|
||||
h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false)
|
||||
h, err := makeServerPipeHandle(l.path, nil, &l.config, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -354,22 +449,13 @@ func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Immediately open and then close a client handle so that the named pipe is
|
||||
// created but not currently accepting connections.
|
||||
h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
||||
if err != nil {
|
||||
syscall.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
syscall.Close(h2)
|
||||
l := &win32PipeListener{
|
||||
firstHandle: h,
|
||||
path: path,
|
||||
securityDescriptor: sd,
|
||||
config: *c,
|
||||
acceptCh: make(chan (chan acceptResponse)),
|
||||
closeCh: make(chan int),
|
||||
doneCh: make(chan int),
|
||||
firstHandle: h,
|
||||
path: path,
|
||||
config: *c,
|
||||
acceptCh: make(chan (chan acceptResponse)),
|
||||
closeCh: make(chan int),
|
||||
doneCh: make(chan int),
|
||||
}
|
||||
go l.listenerRoutine()
|
||||
return l, nil
|
||||
|
||||
235
vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
generated
vendored
Normal file
235
vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
// Package guid provides a GUID type. The backing structure for a GUID is
|
||||
// identical to that used by the golang.org/x/sys/windows GUID type.
|
||||
// There are two main binary encodings used for a GUID, the big-endian encoding,
|
||||
// and the Windows (mixed-endian) encoding. See here for details:
|
||||
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding
|
||||
package guid
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Variant specifies which GUID variant (or "type") of the GUID. It determines
|
||||
// how the entirety of the rest of the GUID is interpreted.
|
||||
type Variant uint8
|
||||
|
||||
// The variants specified by RFC 4122.
|
||||
const (
|
||||
// VariantUnknown specifies a GUID variant which does not conform to one of
|
||||
// the variant encodings specified in RFC 4122.
|
||||
VariantUnknown Variant = iota
|
||||
VariantNCS
|
||||
VariantRFC4122
|
||||
VariantMicrosoft
|
||||
VariantFuture
|
||||
)
|
||||
|
||||
// Version specifies how the bits in the GUID were generated. For instance, a
|
||||
// version 4 GUID is randomly generated, and a version 5 is generated from the
|
||||
// hash of an input string.
|
||||
type Version uint8
|
||||
|
||||
var _ = (encoding.TextMarshaler)(GUID{})
|
||||
var _ = (encoding.TextUnmarshaler)(&GUID{})
|
||||
|
||||
// GUID represents a GUID/UUID. It has the same structure as
|
||||
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
|
||||
// that type. It is defined as its own type so that stringification and
|
||||
// marshaling can be supported. The representation matches that used by native
|
||||
// Windows code.
|
||||
type GUID windows.GUID
|
||||
|
||||
// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
|
||||
func NewV4() (GUID, error) {
|
||||
var b [16]byte
|
||||
if _, err := rand.Read(b[:]); err != nil {
|
||||
return GUID{}, err
|
||||
}
|
||||
|
||||
g := FromArray(b)
|
||||
g.setVersion(4) // Version 4 means randomly generated.
|
||||
g.setVariant(VariantRFC4122)
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
// NewV5 returns a new version 5 (generated from a string via SHA-1 hashing)
|
||||
// GUID, as defined by RFC 4122. The RFC is unclear on the encoding of the name,
|
||||
// and the sample code treats it as a series of bytes, so we do the same here.
|
||||
//
|
||||
// Some implementations, such as those found on Windows, treat the name as a
|
||||
// big-endian UTF16 stream of bytes. If that is desired, the string can be
|
||||
// encoded as such before being passed to this function.
|
||||
func NewV5(namespace GUID, name []byte) (GUID, error) {
|
||||
b := sha1.New()
|
||||
namespaceBytes := namespace.ToArray()
|
||||
b.Write(namespaceBytes[:])
|
||||
b.Write(name)
|
||||
|
||||
a := [16]byte{}
|
||||
copy(a[:], b.Sum(nil))
|
||||
|
||||
g := FromArray(a)
|
||||
g.setVersion(5) // Version 5 means generated from a string.
|
||||
g.setVariant(VariantRFC4122)
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func fromArray(b [16]byte, order binary.ByteOrder) GUID {
|
||||
var g GUID
|
||||
g.Data1 = order.Uint32(b[0:4])
|
||||
g.Data2 = order.Uint16(b[4:6])
|
||||
g.Data3 = order.Uint16(b[6:8])
|
||||
copy(g.Data4[:], b[8:16])
|
||||
return g
|
||||
}
|
||||
|
||||
func (g GUID) toArray(order binary.ByteOrder) [16]byte {
|
||||
b := [16]byte{}
|
||||
order.PutUint32(b[0:4], g.Data1)
|
||||
order.PutUint16(b[4:6], g.Data2)
|
||||
order.PutUint16(b[6:8], g.Data3)
|
||||
copy(b[8:16], g.Data4[:])
|
||||
return b
|
||||
}
|
||||
|
||||
// FromArray constructs a GUID from a big-endian encoding array of 16 bytes.
|
||||
func FromArray(b [16]byte) GUID {
|
||||
return fromArray(b, binary.BigEndian)
|
||||
}
|
||||
|
||||
// ToArray returns an array of 16 bytes representing the GUID in big-endian
|
||||
// encoding.
|
||||
func (g GUID) ToArray() [16]byte {
|
||||
return g.toArray(binary.BigEndian)
|
||||
}
|
||||
|
||||
// FromWindowsArray constructs a GUID from a Windows encoding array of bytes.
|
||||
func FromWindowsArray(b [16]byte) GUID {
|
||||
return fromArray(b, binary.LittleEndian)
|
||||
}
|
||||
|
||||
// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows
|
||||
// encoding.
|
||||
func (g GUID) ToWindowsArray() [16]byte {
|
||||
return g.toArray(binary.LittleEndian)
|
||||
}
|
||||
|
||||
func (g GUID) String() string {
|
||||
return fmt.Sprintf(
|
||||
"%08x-%04x-%04x-%04x-%012x",
|
||||
g.Data1,
|
||||
g.Data2,
|
||||
g.Data3,
|
||||
g.Data4[:2],
|
||||
g.Data4[2:])
|
||||
}
|
||||
|
||||
// FromString parses a string containing a GUID and returns the GUID. The only
|
||||
// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
|
||||
// format.
|
||||
func FromString(s string) (GUID, error) {
|
||||
if len(s) != 36 {
|
||||
return GUID{}, fmt.Errorf("invalid GUID %q", s)
|
||||
}
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return GUID{}, fmt.Errorf("invalid GUID %q", s)
|
||||
}
|
||||
|
||||
var g GUID
|
||||
|
||||
data1, err := strconv.ParseUint(s[0:8], 16, 32)
|
||||
if err != nil {
|
||||
return GUID{}, fmt.Errorf("invalid GUID %q", s)
|
||||
}
|
||||
g.Data1 = uint32(data1)
|
||||
|
||||
data2, err := strconv.ParseUint(s[9:13], 16, 16)
|
||||
if err != nil {
|
||||
return GUID{}, fmt.Errorf("invalid GUID %q", s)
|
||||
}
|
||||
g.Data2 = uint16(data2)
|
||||
|
||||
data3, err := strconv.ParseUint(s[14:18], 16, 16)
|
||||
if err != nil {
|
||||
return GUID{}, fmt.Errorf("invalid GUID %q", s)
|
||||
}
|
||||
g.Data3 = uint16(data3)
|
||||
|
||||
for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} {
|
||||
v, err := strconv.ParseUint(s[x:x+2], 16, 8)
|
||||
if err != nil {
|
||||
return GUID{}, fmt.Errorf("invalid GUID %q", s)
|
||||
}
|
||||
g.Data4[i] = uint8(v)
|
||||
}
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *GUID) setVariant(v Variant) {
|
||||
d := g.Data4[0]
|
||||
switch v {
|
||||
case VariantNCS:
|
||||
d = (d & 0x7f)
|
||||
case VariantRFC4122:
|
||||
d = (d & 0x3f) | 0x80
|
||||
case VariantMicrosoft:
|
||||
d = (d & 0x1f) | 0xc0
|
||||
case VariantFuture:
|
||||
d = (d & 0x0f) | 0xe0
|
||||
case VariantUnknown:
|
||||
fallthrough
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid variant: %d", v))
|
||||
}
|
||||
g.Data4[0] = d
|
||||
}
|
||||
|
||||
// Variant returns the GUID variant, as defined in RFC 4122.
|
||||
func (g GUID) Variant() Variant {
|
||||
b := g.Data4[0]
|
||||
if b&0x80 == 0 {
|
||||
return VariantNCS
|
||||
} else if b&0xc0 == 0x80 {
|
||||
return VariantRFC4122
|
||||
} else if b&0xe0 == 0xc0 {
|
||||
return VariantMicrosoft
|
||||
} else if b&0xe0 == 0xe0 {
|
||||
return VariantFuture
|
||||
}
|
||||
return VariantUnknown
|
||||
}
|
||||
|
||||
func (g *GUID) setVersion(v Version) {
|
||||
g.Data3 = (g.Data3 & 0x0fff) | (uint16(v) << 12)
|
||||
}
|
||||
|
||||
// Version returns the GUID version, as defined in RFC 4122.
|
||||
func (g GUID) Version() Version {
|
||||
return Version((g.Data3 & 0xF000) >> 12)
|
||||
}
|
||||
|
||||
// MarshalText returns the textual representation of the GUID.
|
||||
func (g GUID) MarshalText() ([]byte, error) {
|
||||
return []byte(g.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText takes the textual representation of a GUID, and unmarhals it
|
||||
// into this GUID.
|
||||
func (g *GUID) UnmarshalText(text []byte) error {
|
||||
g2, err := FromString(string(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*g = g2
|
||||
return nil
|
||||
}
|
||||
2
vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
2
vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
@@ -1,3 +1,3 @@
|
||||
package winio
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go
|
||||
|
||||
88
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
88
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
@@ -1,4 +1,4 @@
|
||||
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package winio
|
||||
|
||||
@@ -38,19 +38,25 @@ func errnoErr(e syscall.Errno) error {
|
||||
|
||||
var (
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
|
||||
modntdll = windows.NewLazySystemDLL("ntdll.dll")
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
|
||||
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
|
||||
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
|
||||
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
|
||||
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
|
||||
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
|
||||
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
|
||||
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
|
||||
procCreateFileW = modkernel32.NewProc("CreateFileW")
|
||||
procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW")
|
||||
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
|
||||
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
|
||||
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
|
||||
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile")
|
||||
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
|
||||
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
|
||||
procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl")
|
||||
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
||||
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
||||
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
|
||||
@@ -69,6 +75,7 @@ var (
|
||||
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
||||
procBackupRead = modkernel32.NewProc("BackupRead")
|
||||
procBackupWrite = modkernel32.NewProc("BackupWrite")
|
||||
procbind = modws2_32.NewProc("bind")
|
||||
)
|
||||
|
||||
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
@@ -120,6 +127,24 @@ func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err erro
|
||||
return
|
||||
}
|
||||
|
||||
func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
|
||||
var _p0 uint32
|
||||
if wait {
|
||||
_p0 = 1
|
||||
} else {
|
||||
_p0 = 0
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
|
||||
if r1 == 0 {
|
||||
@@ -176,27 +201,6 @@ func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityA
|
||||
return
|
||||
}
|
||||
|
||||
func waitNamedPipe(name string, timeout uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _waitNamedPipe(_p0, timeout)
|
||||
}
|
||||
|
||||
func _waitNamedPipe(name *uint16, timeout uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
|
||||
if r1 == 0 {
|
||||
@@ -227,6 +231,32 @@ func localAlloc(uFlags uint32, length uint32) (ptr uintptr) {
|
||||
return
|
||||
}
|
||||
|
||||
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) {
|
||||
r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0)
|
||||
status = ntstatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlNtStatusToDosError(status ntstatus) (winerr error) {
|
||||
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
|
||||
if r0 != 0 {
|
||||
winerr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) {
|
||||
r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
|
||||
status = ntstatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) {
|
||||
r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
|
||||
status = ntstatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(accountName)
|
||||
@@ -518,3 +548,15 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
|
||||
if r1 == socketError {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
7
vendor/github.com/aktau/github-release/.gitignore
generated
vendored
Normal file
7
vendor/github.com/aktau/github-release/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/github-release
|
||||
/go-app
|
||||
|
||||
*.exe
|
||||
|
||||
/bin
|
||||
/var/cache
|
||||
10
vendor/github.com/aktau/github-release/CONTRIBUTING.md
generated
vendored
Normal file
10
vendor/github.com/aktau/github-release/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
## Releasing new versions
|
||||
|
||||
1) Bump the version in github/version.go
|
||||
|
||||
2) Add a commit with message "github-release v1.2.3"
|
||||
|
||||
3) Run `git tag v1.2.3` where "1.2.3" stands in for the version you actually
|
||||
want.
|
||||
|
||||
4) Run `make release`. Be sure to have `GITHUB_TOKEN` set in your environment.
|
||||
89
vendor/github.com/aktau/github-release/Gopkg.lock
generated
vendored
Normal file
89
vendor/github.com/aktau/github-release/Gopkg.lock
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6f9339c912bbdda81302633ad7e99a28dfa5a639c864061f1929510a9a64aa74"
|
||||
name = "github.com/dustin/go-humanize"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "9f541cc9db5d55bce703bd99987c9d5cb8eea45e"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d"
|
||||
name = "github.com/go-stack/stack"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5c56664d98f37f0ee54bf572b0b189a3910c34c31052fc7d58b282c449b079fb"
|
||||
name = "github.com/inconshreveable/log15"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "b30bc20e4fd12cec79a9aae62e91cfcf458bd253"
|
||||
version = "v2.15"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:de0adde670b2119824a1252b61a0e989669f8b24af874e399bec0e0538b2f928"
|
||||
name = "github.com/kevinburke/rest"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "0d2892b400f81cdfb979e2f718e6070fae17a507"
|
||||
version = "2.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0109cf4321a15313ec895f42e723e1f76121c6975ea006abfa20012272ec0937"
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "68e95eba382c972aafde02ead2cd2426a8a92480"
|
||||
version = "v0.1.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0c58d31abe2a2ccb429c559b6292e7df89dcda675456fecc282fa90aa08273eb"
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "7b513a986450394f7bbf1476909911b3aa3a55ce"
|
||||
version = "v0.0.12"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f2dda646a25cf3b9f6f6931d86ef0b85b64979697e5833cdcbc0c23f2586d996"
|
||||
name = "github.com/tomnomnom/linkheader"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "02ca5825eb8097f10d9cc53da78481a85ad84e04"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d1d1683ae67edaebf7e51151f934943bf2f53b71260818d843ab7233aa145533"
|
||||
name = "github.com/voxelbrain/goptions"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "26cb8b04692384f4dc269de3b5fcf3e2ef78573e"
|
||||
version = "2.5.11"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8cab10971112233c82c83683a517378038eba1c20e71b29c592b73fa212437b3"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"internal/unsafeheader",
|
||||
"unix",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "bc7a7d42d5c30f4d0fe808715c002826ce2c624e"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/dustin/go-humanize",
|
||||
"github.com/kevinburke/rest",
|
||||
"github.com/tomnomnom/linkheader",
|
||||
"github.com/voxelbrain/goptions",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
24
vendor/github.com/aktau/github-release/Gopkg.toml
generated
vendored
Normal file
24
vendor/github.com/aktau/github-release/Gopkg.toml
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/dustin/go-humanize"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/kevinburke/rest"
|
||||
version = "2.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tomnomnom/linkheader"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/voxelbrain/goptions"
|
||||
version = "2.5.11"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
21
vendor/github.com/aktau/github-release/LICENSE
generated
vendored
Normal file
21
vendor/github.com/aktau/github-release/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2017 Nicolas Hillegeer
|
||||
Copyright (c) 2020 Meter, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
97
vendor/github.com/aktau/github-release/Makefile
generated
vendored
Normal file
97
vendor/github.com/aktau/github-release/Makefile
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
SHELL=/bin/bash -o pipefail
|
||||
|
||||
LAST_TAG := $(shell git describe --abbrev=0 --tags)
|
||||
|
||||
USER := github-release
|
||||
EXECUTABLE := github-release
|
||||
|
||||
# only include the amd64 binaries, otherwise the github release will become
|
||||
# too big
|
||||
UNIX_EXECUTABLES := \
|
||||
darwin/amd64/$(EXECUTABLE) \
|
||||
freebsd/amd64/$(EXECUTABLE) \
|
||||
linux/amd64/$(EXECUTABLE)
|
||||
WIN_EXECUTABLES := \
|
||||
windows/amd64/$(EXECUTABLE).exe
|
||||
|
||||
COMPRESSED_EXECUTABLES=$(UNIX_EXECUTABLES:%=%.bz2) $(WIN_EXECUTABLES:%.exe=%.zip)
|
||||
COMPRESSED_EXECUTABLE_TARGETS=$(COMPRESSED_EXECUTABLES:%=bin/%)
|
||||
|
||||
UPLOAD_CMD = bin/tmp/$(EXECUTABLE) upload -u $(USER) -r $(EXECUTABLE) -t $(LAST_TAG) -n $(subst /,-,$(FILE)) -f bin/$(FILE)
|
||||
|
||||
all: $(EXECUTABLE)
|
||||
|
||||
# the executable used to perform the upload, dogfooding and all...
|
||||
bin/tmp/$(EXECUTABLE):
|
||||
go build -v -o "$@"
|
||||
|
||||
# arm
|
||||
bin/linux/arm/5/$(EXECUTABLE):
|
||||
GOARM=5 GOARCH=arm GOOS=linux go build -o "$@"
|
||||
bin/linux/arm/7/$(EXECUTABLE):
|
||||
GOARM=7 GOARCH=arm GOOS=linux go build -o "$@"
|
||||
|
||||
# 386
|
||||
bin/darwin/386/$(EXECUTABLE):
|
||||
GOARCH=386 GOOS=darwin go build -o "$@"
|
||||
bin/linux/386/$(EXECUTABLE):
|
||||
GOARCH=386 GOOS=linux go build -o "$@"
|
||||
bin/windows/386/$(EXECUTABLE):
|
||||
GOARCH=386 GOOS=windows go build -o "$@"
|
||||
|
||||
# amd64
|
||||
bin/freebsd/amd64/$(EXECUTABLE):
|
||||
GOARCH=amd64 GOOS=freebsd go build -o "$@"
|
||||
bin/darwin/amd64/$(EXECUTABLE):
|
||||
GOARCH=amd64 GOOS=darwin go build -o "$@"
|
||||
bin/linux/amd64/$(EXECUTABLE):
|
||||
GOARCH=amd64 GOOS=linux go build -o "$@"
|
||||
bin/windows/amd64/$(EXECUTABLE).exe:
|
||||
GOARCH=amd64 GOOS=windows go build -o "$@"
|
||||
|
||||
# compressed artifacts, makes a huge difference (Go executable is ~9MB,
|
||||
# after compressing ~2MB)
|
||||
%.bz2: %
|
||||
bzip2 --keep "$<"
|
||||
%.zip: %.exe
|
||||
zip "$@" "$<"
|
||||
|
||||
# git tag -a v$(RELEASE) -m 'release $(RELEASE)'
|
||||
release: clean
|
||||
ifndef GITHUB_TOKEN
|
||||
@echo "Please set GITHUB_TOKEN in the environment to perform a release"
|
||||
exit 1
|
||||
endif
|
||||
docker run --rm --volume $(PWD)/var/cache:/root/.cache/go-build \
|
||||
--env GITHUB_TOKEN=$(GITHUB_TOKEN) \
|
||||
--volume "$(PWD)":/go/src/github.com/github-release/github-release \
|
||||
--workdir /go/src/github.com/github-release/github-release \
|
||||
meterup/ubuntu-golang:latest \
|
||||
./release \
|
||||
"$(MAKE) bin/tmp/$(EXECUTABLE) $(COMPRESSED_EXECUTABLE_TARGETS) && \
|
||||
git log --format=%B $(LAST_TAG) -1 | \
|
||||
bin/tmp/$(EXECUTABLE) release -u $(USER) -r $(EXECUTABLE) \
|
||||
-t $(LAST_TAG) -n $(LAST_TAG) -d - || true && \
|
||||
$(foreach FILE,$(COMPRESSED_EXECUTABLES),$(UPLOAD_CMD);)"
|
||||
|
||||
# install and/or update all dependencies, run this from the project directory
|
||||
# go get -u ./...
|
||||
# go test -i ./
|
||||
dep:
|
||||
go list -f '{{join .Deps "\n"}}' | xargs go list -e -f '{{if not .Standard}}{{.ImportPath}}{{end}}' | xargs go get -u
|
||||
|
||||
$(EXECUTABLE): dep
|
||||
go build -o "$@"
|
||||
|
||||
install:
|
||||
go install
|
||||
|
||||
clean:
|
||||
rm go-app || true
|
||||
rm $(EXECUTABLE) || true
|
||||
rm -rf bin/
|
||||
|
||||
test:
|
||||
go test ./...
|
||||
|
||||
.PHONY: clean release dep install
|
||||
131
vendor/github.com/aktau/github-release/README.md
generated
vendored
Normal file
131
vendor/github.com/aktau/github-release/README.md
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
github-release
|
||||
==============
|
||||
|
||||
A small commandline app written in Go that allows you to easily create
|
||||
and delete releases of your projects on Github. In addition it allows
|
||||
you to attach files to those releases.
|
||||
|
||||
It interacts with the [github releases API][releases-api]. Though it's entirely
|
||||
possible to [do all these things with cURL][curl], it's not really that
|
||||
user-friendly. For example, you need to first query the API to find the id of
|
||||
the release you want, before you can upload an artifact. `github-release` takes
|
||||
care of those little details.
|
||||
|
||||
[curl]: https://github.com/blog/1645-releases-api-preview
|
||||
[releases-api]: https://developer.github.com/v3/repos/releases
|
||||
|
||||
It might still be a bit rough around the edges, pull requests are
|
||||
welcome!
|
||||
|
||||
How to install
|
||||
==============
|
||||
|
||||
If you don't have the Go toolset installed, and you don't want to, but
|
||||
still want to use the app, you can download binaries for your platform
|
||||
on the [releases
|
||||
page](https://github.com/github-release/github-release/releases/latest). Yes, that's
|
||||
dogfooding, check the makefile!
|
||||
|
||||
If you have Go installed, you can just do:
|
||||
|
||||
```sh
|
||||
go get github.com/github-release/github-release
|
||||
```
|
||||
|
||||
This will automatically download, compile and install the app.
|
||||
|
||||
After that you should have a `github-release` executable in your
|
||||
`$GOPATH/bin`.
|
||||
|
||||
How to use
|
||||
==========
|
||||
|
||||
**NOTE**: for these examples I've [created a github token][token] and set it as
|
||||
the env variable `GITHUB_TOKEN`. `github-release` will automatically pick it up
|
||||
from the environment so that you don't have to pass it as an argument.
|
||||
|
||||
[token]: https://help.github.com/articles/creating-an-access-token-for-command-line-use
|
||||
|
||||
```sh
|
||||
# set your token
|
||||
export GITHUB_TOKEN=...
|
||||
|
||||
# check the help
|
||||
$ github-release --help
|
||||
|
||||
# make your tag and upload
|
||||
$ git tag ... && git push --tags
|
||||
|
||||
# check the current tags and existing releases of the repo
|
||||
$ github-release info -u aktau -r gofinance
|
||||
git tags:
|
||||
- v0.1.0 (commit: https://api.github.com/repos/aktau/gofinance/commits/f562727ce83ce8971a8569a1879219e41d56a756)
|
||||
releases:
|
||||
- v0.1.0, name: 'hoary ungar', description: 'something something dark side 2', id: 166740, tagged: 29/01/2014 at 14:27, published: 30/01/2014 at 16:20, draft: ✔, prerelease: ✗
|
||||
- artifact: github.go, downloads: 0, state: uploaded, type: application/octet-stream, size: 1.9KB, id: 68616
|
||||
|
||||
# create a formal release
|
||||
$ github-release release \
|
||||
--user aktau \
|
||||
--repo gofinance \
|
||||
--tag v0.1.0 \
|
||||
--name "the wolf of source street" \
|
||||
--description "Not a movie, contrary to popular opinion. Still, my first release!" \
|
||||
--pre-release
|
||||
|
||||
# you've made a mistake, but you can edit the release without
|
||||
# having to delete it first (this also means you can edit without having
|
||||
# to upload your files again)
|
||||
$ github-release edit \
|
||||
--user aktau \
|
||||
--repo gofinance \
|
||||
--tag v0.1.0 \
|
||||
--name "Highlander II: The Quickening" \
|
||||
--description "This is the actual description!"
|
||||
|
||||
# upload a file, for example the OSX/AMD64 binary of my gofinance app
|
||||
$ github-release upload \
|
||||
--user aktau \
|
||||
--repo gofinance \
|
||||
--tag v0.1.0 \
|
||||
--name "gofinance-osx-amd64" \
|
||||
--file bin/darwin/amd64/gofinance
|
||||
|
||||
# upload other files...
|
||||
$ github-release upload ...
|
||||
|
||||
# you're not happy with it, so delete it
|
||||
$ github-release delete \
|
||||
--user aktau \
|
||||
--repo gofinance \
|
||||
--tag v0.1.0
|
||||
```
|
||||
|
||||
GitHub Enterprise Support
|
||||
=========================
|
||||
You can point to a different GitHub API endpoint via the environment variable ```GITHUB_API```:
|
||||
|
||||
```
|
||||
export GITHUB_API=http://github.company.com/api/v3
|
||||
```
|
||||
|
||||
Used libraries
|
||||
==============
|
||||
|
||||
| Package | Description | License |
|
||||
| ------------------------------------------------------------------------ | ------------------- | ------- |
|
||||
| [github.com/dustin/go-humanize](https://github.com/dustin/go-humanize) | humanize file sizes | MIT |
|
||||
| [github.com/tomnomnom/linkheader](https://github.com/tomnomnom/linkheader) | GH API pagination | MIT |
|
||||
| [github.com/voxelbrain/goptions](https://github.com/voxelbrain/goptions) | option parsing | BSD |
|
||||
| [github.com/kevinburke/rest](https://github.com/kevinburke/rest) | HTTP client | MIT |
|
||||
|
||||
Todo
|
||||
====
|
||||
|
||||
- Check if an artifact is already uploaded before starting a new upload
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
Copyright (c) 2014-2017, Nicolas Hillegeer. All rights reserved.
|
||||
Copyright (c) 2020, Meter, Inc. All rights reserved.
|
||||
58
vendor/github.com/aktau/github-release/assets.go
generated
vendored
Normal file
58
vendor/github.com/aktau/github-release/assets.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/github-release/github-release/github"
|
||||
)
|
||||
|
||||
const (
|
||||
// GET /repos/:owner/:repo/releases/assets/:id
|
||||
// DELETE /repos/:owner/:repo/releases/assets/:id
|
||||
ASSET_URI = "/repos/%s/%s/releases/assets/%d"
|
||||
|
||||
// API: https://developer.github.com/v3/repos/releases/#list-assets-for-a-release
|
||||
// GET /repos/:owner/:repo/releases/:id/assets
|
||||
ASSET_RELEASE_LIST_URI = "/repos/%s/%s/releases/%d/assets"
|
||||
)
|
||||
|
||||
type Asset struct {
|
||||
Url string `json:"url"`
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ContentType string `json:"content_type"`
|
||||
State string `json:"state"`
|
||||
Size uint64 `json:"size"`
|
||||
Downloads uint64 `json:"download_count"`
|
||||
Created time.Time `json:"created_at"`
|
||||
Published time.Time `json:"published_at"`
|
||||
}
|
||||
|
||||
// findAsset returns the asset if an asset with name can be found in assets,
|
||||
// otherwise returns nil.
|
||||
func findAsset(assets []Asset, name string) *Asset {
|
||||
for _, asset := range assets {
|
||||
if asset.Name == name {
|
||||
return &asset
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete sends a HTTP DELETE request for the given asset to Github. Returns
|
||||
// nil if the asset was deleted OR there was nothing to delete.
|
||||
func (a *Asset) Delete(user, repo, token string) error {
|
||||
URL := nvls(EnvApiEndpoint, github.DefaultBaseURL) +
|
||||
fmt.Sprintf(ASSET_URI, user, repo, a.Id)
|
||||
resp, err := github.DoAuthRequest("DELETE", URL, "application/json", token, nil, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete asset %s (ID: %d), HTTP error: %b", a.Name, a.Id, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return fmt.Errorf("failed to delete asset %s (ID: %d), status: %s", a.Name, a.Id, resp.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
489
vendor/github.com/aktau/github-release/cmd.go
generated
vendored
Normal file
489
vendor/github.com/aktau/github-release/cmd.go
generated
vendored
Normal file
@@ -0,0 +1,489 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/github-release/github-release/github"
|
||||
)
|
||||
|
||||
func infocmd(opt Options) error {
|
||||
user := nvls(opt.Info.User, EnvUser)
|
||||
authUser := nvls(opt.Info.AuthUser, EnvAuthUser)
|
||||
repo := nvls(opt.Info.Repo, EnvRepo)
|
||||
token := nvls(opt.Info.Token, EnvToken)
|
||||
tag := opt.Info.Tag
|
||||
|
||||
if user == "" || repo == "" {
|
||||
return fmt.Errorf("user and repo need to be passed as arguments")
|
||||
}
|
||||
|
||||
// Find regular git tags.
|
||||
foundTags, err := Tags(user, repo, authUser, token)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fetch tags, %v", err)
|
||||
}
|
||||
if len(foundTags) == 0 {
|
||||
return fmt.Errorf("no tags available for %v/%v", user, repo)
|
||||
}
|
||||
|
||||
tags := foundTags[:0]
|
||||
for _, t := range foundTags {
|
||||
// If the user only requested one tag, filter out the rest.
|
||||
if tag == "" || t.Name == tag {
|
||||
tags = append(tags, t)
|
||||
}
|
||||
}
|
||||
|
||||
renderer := renderInfoText
|
||||
|
||||
if opt.Info.JSON {
|
||||
renderer = renderInfoJSON
|
||||
}
|
||||
|
||||
// List releases + assets.
|
||||
var releases []Release
|
||||
if tag == "" {
|
||||
// Get all releases.
|
||||
vprintf("%v/%v: getting information for all releases\n", user, repo)
|
||||
releases, err = Releases(user, repo, authUser, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Get only one release.
|
||||
vprintf("%v/%v/%v: getting information for the release\n", user, repo, tag)
|
||||
release, err := ReleaseOfTag(user, repo, tag, authUser, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
releases = []Release{*release}
|
||||
}
|
||||
|
||||
return renderer(tags, releases)
|
||||
}
|
||||
|
||||
func renderInfoText(tags []Tag, releases []Release) error {
|
||||
fmt.Println("tags:")
|
||||
for _, tag := range tags {
|
||||
fmt.Println("-", &tag)
|
||||
}
|
||||
|
||||
fmt.Println("releases:")
|
||||
for _, release := range releases {
|
||||
fmt.Println("-", &release)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func renderInfoJSON(tags []Tag, releases []Release) error {
|
||||
out := struct {
|
||||
Tags []Tag
|
||||
Releases []Release
|
||||
}{
|
||||
Tags: tags,
|
||||
Releases: releases,
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(&out)
|
||||
}
|
||||
|
||||
func uploadcmd(opt Options) error {
|
||||
user := nvls(opt.Upload.User, EnvUser)
|
||||
authUser := nvls(opt.Upload.AuthUser, EnvAuthUser)
|
||||
repo := nvls(opt.Upload.Repo, EnvRepo)
|
||||
token := nvls(opt.Upload.Token, EnvToken)
|
||||
tag := opt.Upload.Tag
|
||||
name := opt.Upload.Name
|
||||
label := opt.Upload.Label
|
||||
file := opt.Upload.File
|
||||
|
||||
vprintln("uploading...")
|
||||
|
||||
if file == nil {
|
||||
return fmt.Errorf("provided file was not valid")
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if err := ValidateCredentials(user, repo, token, tag); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find the release corresponding to the entered tag, if any.
|
||||
rel, err := ReleaseOfTag(user, repo, tag, authUser, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the user has attempted to upload this asset before, someone could
|
||||
// expect it to be present in the release struct (rel.Assets). However,
|
||||
// we have to separately ask for the specific assets of this release.
|
||||
// Reason: the assets in the Release struct do not contain incomplete
|
||||
// uploads (which regrettably happen often using the Github API). See
|
||||
// issue #26.
|
||||
var assets []Asset
|
||||
client := github.NewClient(authUser, token, nil)
|
||||
client.SetBaseURL(EnvApiEndpoint)
|
||||
err = client.Get(fmt.Sprintf(ASSET_RELEASE_LIST_URI, user, repo, rel.Id), &assets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Incomplete (failed) uploads will have their state set to new. These
|
||||
// assets are (AFAIK) useless in all cases. The only thing they will do
|
||||
// is prevent the upload of another asset of the same name. To work
|
||||
// around this GH API weirdness, let's just delete assets if:
|
||||
//
|
||||
// 1. Their state is new.
|
||||
// 2. The user explicitly asked to delete/replace the asset with -R.
|
||||
if asset := findAsset(assets, name); asset != nil &&
|
||||
(asset.State == "new" || opt.Upload.Replace) {
|
||||
vprintf("asset (id: %d) already existed in state %s: removing...\n", asset.Id, asset.Name)
|
||||
if err := asset.Delete(user, repo, token); err != nil {
|
||||
return fmt.Errorf("could not replace asset: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("name", name)
|
||||
if label != "" {
|
||||
v.Set("label", label)
|
||||
}
|
||||
|
||||
url := rel.CleanUploadUrl() + "?" + v.Encode()
|
||||
|
||||
resp, err := github.DoAuthRequest("POST", url, "application/octet-stream",
|
||||
token, nil, file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't create upload request to %v, %v", url, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
vprintln("RESPONSE:", resp)
|
||||
|
||||
var r io.Reader = resp.Body
|
||||
if VERBOSITY != 0 {
|
||||
r = io.TeeReader(r, os.Stderr)
|
||||
}
|
||||
var asset *Asset
|
||||
// For HTTP status 201 and 502, Github will return a JSON encoding of
|
||||
// the (partially) created asset.
|
||||
if resp.StatusCode == http.StatusBadGateway || resp.StatusCode == http.StatusCreated {
|
||||
vprintf("ASSET: ")
|
||||
asset = new(Asset)
|
||||
if err := json.NewDecoder(r).Decode(&asset); err != nil {
|
||||
return fmt.Errorf("upload failed (%s), could not unmarshal asset (err: %v)", resp.Status, err)
|
||||
}
|
||||
} else {
|
||||
vprintf("BODY: ")
|
||||
if msg, err := ToMessage(r); err == nil {
|
||||
return fmt.Errorf("could not upload, status code (%s), %v",
|
||||
resp.Status, msg)
|
||||
}
|
||||
return fmt.Errorf("could not upload, status code (%s)", resp.Status)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusBadGateway {
|
||||
// 502 means the upload failed, but GitHub still retains metadata
|
||||
// (an asset in state "new"). Attempt to delete that now since it
|
||||
// would clutter the list of release assets.
|
||||
vprintf("asset (id: %d) failed to upload, it's now in state %s: removing...\n", asset.Id, asset.Name)
|
||||
if err := asset.Delete(user, repo, token); err != nil {
|
||||
return fmt.Errorf("upload failed (%s), could not delete partially uploaded asset (ID: %d, err: %v) in order to cleanly reset GH API state, please try again", resp.Status, asset.Id, err)
|
||||
}
|
||||
return fmt.Errorf("could not upload, status code (%s)", resp.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func downloadcmd(opt Options) error {
|
||||
user := nvls(opt.Download.User, EnvUser)
|
||||
authUser := nvls(opt.Download.AuthUser, EnvAuthUser)
|
||||
repo := nvls(opt.Download.Repo, EnvRepo)
|
||||
token := nvls(opt.Download.Token, EnvToken)
|
||||
tag := opt.Download.Tag
|
||||
name := opt.Download.Name
|
||||
latest := opt.Download.Latest
|
||||
|
||||
vprintln("downloading...")
|
||||
|
||||
if err := ValidateTarget(user, repo, tag, latest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find the release corresponding to the entered tag, if any.
|
||||
var rel *Release
|
||||
var err error
|
||||
if latest {
|
||||
rel, err = LatestRelease(user, repo, authUser, token)
|
||||
} else {
|
||||
rel, err = ReleaseOfTag(user, repo, tag, authUser, token)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
asset := findAsset(rel.Assets, name)
|
||||
if asset == nil {
|
||||
return fmt.Errorf("coud not find asset named %s", name)
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
if token == "" {
|
||||
// Use the regular github.com site if we don't have a token.
|
||||
resp, err = http.Get("https://github.com" + fmt.Sprintf("/%s/%s/releases/download/%s/%s", user, repo, tag, name))
|
||||
} else {
|
||||
url := nvls(EnvApiEndpoint, github.DefaultBaseURL) + fmt.Sprintf(ASSET_URI, user, repo, asset.Id)
|
||||
resp, err = github.DoAuthRequest("GET", url, "", token, map[string]string{
|
||||
"Accept": "application/octet-stream",
|
||||
}, nil)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fetch releases, %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
vprintln("GET", resp.Request.URL, "->", resp)
|
||||
|
||||
contentLength, err := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("github did not respond with 200 OK but with %v", resp.Status)
|
||||
}
|
||||
|
||||
out := os.Stdout // Pipe the asset to stdout by default.
|
||||
if isCharDevice(out) {
|
||||
// If stdout is a char device, assume it's a TTY (terminal). In this
|
||||
// case, don't pipe th easset to stdout, but create it as a file in
|
||||
// the current working folder.
|
||||
if out, err = os.Create(name); err != nil {
|
||||
return fmt.Errorf("could not create file %s", name)
|
||||
}
|
||||
defer out.Close()
|
||||
}
|
||||
|
||||
return mustCopyN(out, resp.Body, contentLength)
|
||||
}
|
||||
|
||||
// mustCopyN attempts to copy exactly N bytes, if this fails, an error is
|
||||
// returned.
|
||||
func mustCopyN(w io.Writer, r io.Reader, n int64) error {
|
||||
an, err := io.Copy(w, r)
|
||||
if an != n {
|
||||
return fmt.Errorf("data did not match content length %d != %d", an, n)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ValidateTarget(user, repo, tag string, latest bool) error {
|
||||
if user == "" {
|
||||
return fmt.Errorf("empty user")
|
||||
}
|
||||
if repo == "" {
|
||||
return fmt.Errorf("empty repo")
|
||||
}
|
||||
if tag == "" && !latest {
|
||||
return fmt.Errorf("empty tag")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateCredentials(user, repo, token, tag string) error {
|
||||
if err := ValidateTarget(user, repo, tag, false); err != nil {
|
||||
return err
|
||||
}
|
||||
if token == "" {
|
||||
return fmt.Errorf("empty token")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func releasecmd(opt Options) error {
|
||||
cmdopt := opt.Release
|
||||
user := nvls(cmdopt.User, EnvUser)
|
||||
repo := nvls(cmdopt.Repo, EnvRepo)
|
||||
token := nvls(cmdopt.Token, EnvToken)
|
||||
tag := cmdopt.Tag
|
||||
name := nvls(cmdopt.Name, tag)
|
||||
desc := nvls(cmdopt.Desc, tag)
|
||||
target := nvls(cmdopt.Target)
|
||||
draft := cmdopt.Draft
|
||||
prerelease := cmdopt.Prerelease
|
||||
|
||||
vprintln("releasing...")
|
||||
|
||||
if err := ValidateCredentials(user, repo, token, tag); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if we need to read the description from stdin.
|
||||
if desc == "-" {
|
||||
b, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read description from stdin: %v", err)
|
||||
}
|
||||
desc = string(b)
|
||||
}
|
||||
|
||||
params := ReleaseCreate{
|
||||
TagName: tag,
|
||||
TargetCommitish: target,
|
||||
Name: name,
|
||||
Body: desc,
|
||||
Draft: draft,
|
||||
Prerelease: prerelease,
|
||||
}
|
||||
|
||||
/* encode params as json */
|
||||
payload, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't encode release creation params, %v", err)
|
||||
}
|
||||
reader := bytes.NewReader(payload)
|
||||
|
||||
URL := nvls(EnvApiEndpoint, github.DefaultBaseURL) + fmt.Sprintf("/repos/%s/%s/releases", user, repo)
|
||||
resp, err := github.DoAuthRequest("POST", URL, "application/json", token, nil, reader)
|
||||
if err != nil {
|
||||
return fmt.Errorf("while submitting %v, %v", string(payload), err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
vprintln("RESPONSE:", resp)
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
if resp.StatusCode == 422 {
|
||||
return fmt.Errorf("github returned %v (this is probably because the release already exists)",
|
||||
resp.Status)
|
||||
}
|
||||
return fmt.Errorf("github returned %v", resp.Status)
|
||||
}
|
||||
|
||||
if VERBOSITY != 0 {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while reading response, %v", err)
|
||||
}
|
||||
vprintln("BODY:", string(body))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func editcmd(opt Options) error {
|
||||
cmdopt := opt.Edit
|
||||
user := nvls(cmdopt.User, EnvUser)
|
||||
authUser := nvls(cmdopt.AuthUser, EnvAuthUser)
|
||||
repo := nvls(cmdopt.Repo, EnvRepo)
|
||||
token := nvls(cmdopt.Token, EnvToken)
|
||||
tag := cmdopt.Tag
|
||||
name := nvls(cmdopt.Name, tag)
|
||||
desc := nvls(cmdopt.Desc, tag)
|
||||
draft := cmdopt.Draft
|
||||
prerelease := cmdopt.Prerelease
|
||||
|
||||
vprintln("editing...")
|
||||
|
||||
if err := ValidateCredentials(user, repo, token, tag); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
id, err := IdOfTag(user, repo, tag, authUser, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vprintf("release %v has id %v\n", tag, id)
|
||||
|
||||
// Check if we need to read the description from stdin.
|
||||
if desc == "-" {
|
||||
b, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read description from stdin: %v", err)
|
||||
}
|
||||
desc = string(b)
|
||||
}
|
||||
|
||||
/* the release create struct works for editing releases as well */
|
||||
params := ReleaseCreate{
|
||||
TagName: tag,
|
||||
Name: name,
|
||||
Body: desc,
|
||||
Draft: draft,
|
||||
Prerelease: prerelease,
|
||||
}
|
||||
|
||||
/* encode the parameters as JSON, as required by the github API */
|
||||
payload, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't encode release creation params, %v", err)
|
||||
}
|
||||
|
||||
URL := nvls(EnvApiEndpoint, github.DefaultBaseURL) + fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id)
|
||||
resp, err := github.DoAuthRequest("PATCH", URL, "application/json", token, nil, bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
return fmt.Errorf("while submitting %v, %v", string(payload), err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
vprintln("RESPONSE:", resp)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if resp.StatusCode == 422 {
|
||||
return fmt.Errorf("github returned %v (this is probably because the release already exists)",
|
||||
resp.Status)
|
||||
}
|
||||
return fmt.Errorf("github returned unexpected status code %v", resp.Status)
|
||||
}
|
||||
|
||||
if VERBOSITY != 0 {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while reading response, %v", err)
|
||||
}
|
||||
vprintln("BODY:", string(body))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deletecmd(opt Options) error {
|
||||
user, repo, token, tag := nvls(opt.Delete.User, EnvUser),
|
||||
nvls(opt.Delete.Repo, EnvRepo),
|
||||
nvls(opt.Delete.Token, EnvToken),
|
||||
opt.Delete.Tag
|
||||
authUser := nvls(opt.Delete.AuthUser, EnvAuthUser)
|
||||
vprintln("deleting...")
|
||||
|
||||
id, err := IdOfTag(user, repo, tag, authUser, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vprintf("release %v has id %v\n", tag, id)
|
||||
|
||||
baseURL := nvls(EnvApiEndpoint, github.DefaultBaseURL)
|
||||
resp, err := github.DoAuthRequest("DELETE", baseURL+fmt.Sprintf("/repos/%s/%s/releases/%d",
|
||||
user, repo, id), "application/json", token, nil, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("release deletion failed: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return fmt.Errorf("could not delete the release corresponding to tag %s on repo %s/%s",
|
||||
tag, user, repo)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
6
vendor/github.com/aktau/github-release/commit.go
generated
vendored
Normal file
6
vendor/github.com/aktau/github-release/commit.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package main
|
||||
|
||||
type Commit struct {
|
||||
Sha string `json:"sha"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
42
vendor/github.com/aktau/github-release/error.go
generated
vendored
Normal file
42
vendor/github.com/aktau/github-release/error.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/* usually when something goes wrong, github sends something like this back */
|
||||
type Message struct {
|
||||
Message string `json:"message"`
|
||||
Errors []GithubError `json:"errors"`
|
||||
}
|
||||
|
||||
type GithubError struct {
|
||||
Resource string `json:"resource"`
|
||||
Code string `json:"code"`
|
||||
Field string `json:"field"`
|
||||
}
|
||||
|
||||
/* transforms a stream into a Message, if it's valid json */
|
||||
func ToMessage(r io.Reader) (*Message, error) {
|
||||
var msg Message
|
||||
if err := json.NewDecoder(r).Decode(&msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
func (m *Message) String() string {
|
||||
str := fmt.Sprintf("msg: %v, errors: ", m.Message)
|
||||
|
||||
errstr := make([]string, len(m.Errors))
|
||||
for idx, err := range m.Errors {
|
||||
errstr[idx] = fmt.Sprintf("[field: %v, code: %v]",
|
||||
err.Field, err.Code)
|
||||
}
|
||||
|
||||
return str + strings.Join(errstr, ", ")
|
||||
}
|
||||
143
vendor/github.com/aktau/github-release/github-release.go
generated
vendored
Normal file
143
vendor/github.com/aktau/github-release/github-release.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/github-release/github-release/github"
|
||||
"github.com/voxelbrain/goptions"
|
||||
)
|
||||
|
||||
const GH_URL = "https://github.com"
|
||||
|
||||
type Options struct {
|
||||
Help goptions.Help `goptions:"-h, --help, description='Show this help'"`
|
||||
Verbosity []bool `goptions:"-v, --verbose, description='Be verbose'"`
|
||||
Quiet bool `goptions:"-q, --quiet, description='Do not print anything, even errors (except if --verbose is specified)'"`
|
||||
Version bool `goptions:"--version, description='Print version'"`
|
||||
|
||||
goptions.Verbs
|
||||
Download struct {
|
||||
Token string `goptions:"-s, --security-token, description='Github token ($GITHUB_TOKEN if set). required if repo is private.'"`
|
||||
User string `goptions:"-u, --user, description='Github repo user or organisation (required if $GITHUB_USER not set)'"`
|
||||
AuthUser string `goptions:"-a, --auth-user, description='Username for authenticating to the API (falls back to $GITHUB_AUTH_USER or $GITHUB_USER)'"`
|
||||
Repo string `goptions:"-r, --repo, description='Github repo (required if $GITHUB_REPO not set)'"`
|
||||
Latest bool `goptions:"-l, --latest, description='Download latest release (required if tag is not specified)',mutexgroup='input'"`
|
||||
Tag string `goptions:"-t, --tag, description='Git tag to download from (required if latest is not specified)', mutexgroup='input',obligatory"`
|
||||
Name string `goptions:"-n, --name, description='Name of the file', obligatory"`
|
||||
} `goptions:"download"`
|
||||
Upload struct {
|
||||
Token string `goptions:"-s, --security-token, description='Github token (required if $GITHUB_TOKEN not set)'"`
|
||||
User string `goptions:"-u, --user, description='Github repo user or organisation (required if $GITHUB_USER not set)'"`
|
||||
AuthUser string `goptions:"-a, --auth-user, description='Username for authenticating to the API (falls back to $GITHUB_AUTH_USER or $GITHUB_USER)'"`
|
||||
Repo string `goptions:"-r, --repo, description='Github repo (required if $GITHUB_REPO not set)'"`
|
||||
Tag string `goptions:"-t, --tag, description='Git tag to upload to', obligatory"`
|
||||
Name string `goptions:"-n, --name, description='Name of the file', obligatory"`
|
||||
Label string `goptions:"-l, --label, description='Label (description) of the file'"`
|
||||
File *os.File `goptions:"-f, --file, description='File to upload (use - for stdin)', rdonly, obligatory"`
|
||||
Replace bool `goptions:"-R, --replace, description='Replace asset with same name if it already exists (WARNING: not atomic, failure to upload will remove the original asset too)'"`
|
||||
} `goptions:"upload"`
|
||||
Release struct {
|
||||
Token string `goptions:"-s, --security-token, description='Github token (required if $GITHUB_TOKEN not set)'"`
|
||||
User string `goptions:"-u, --user, description='Github repo user or organisation (required if $GITHUB_USER not set)'"`
|
||||
Repo string `goptions:"-r, --repo, description='Github repo (required if $GITHUB_REPO not set)'"`
|
||||
Tag string `goptions:"-t, --tag, obligatory, description='Git tag to create a release from'"`
|
||||
Name string `goptions:"-n, --name, description='Name of the release (defaults to tag)'"`
|
||||
Desc string `goptions:"-d, --description, description='Release description, use - for reading a description from stdin (defaults to tag)'"`
|
||||
Target string `goptions:"-c, --target, description='Commit SHA or branch to create release of (defaults to the repository default branch)'"`
|
||||
Draft bool `goptions:"--draft, description='The release is a draft'"`
|
||||
Prerelease bool `goptions:"-p, --pre-release, description='The release is a pre-release'"`
|
||||
} `goptions:"release"`
|
||||
Edit struct {
|
||||
Token string `goptions:"-s, --security-token, description='Github token (required if $GITHUB_TOKEN not set)'"`
|
||||
User string `goptions:"-u, --user, description='Github repo user or organisation (required if $GITHUB_USER not set)'"`
|
||||
AuthUser string `goptions:"-a, --auth-user, description='Username for authenticating to the API (falls back to $GITHUB_AUTH_USER or $GITHUB_USER)'"`
|
||||
Repo string `goptions:"-r, --repo, description='Github repo (required if $GITHUB_REPO not set)'"`
|
||||
Tag string `goptions:"-t, --tag, obligatory, description='Git tag to edit the release of'"`
|
||||
Name string `goptions:"-n, --name, description='New name of the release (defaults to tag)'"`
|
||||
Desc string `goptions:"-d, --description, description='New release description, use - for reading a description from stdin (defaults to tag)'"`
|
||||
Draft bool `goptions:"--draft, description='The release is a draft'"`
|
||||
Prerelease bool `goptions:"-p, --pre-release, description='The release is a pre-release'"`
|
||||
} `goptions:"edit"`
|
||||
Delete struct {
|
||||
Token string `goptions:"-s, --security-token, description='Github token (required if $GITHUB_TOKEN not set)'"`
|
||||
User string `goptions:"-u, --user, description='Github repo user or organisation (required if $GITHUB_USER not set)'"`
|
||||
AuthUser string `goptions:"-a, --auth-user, description='Username for authenticating to the API (falls back to $GITHUB_AUTH_USER or $GITHUB_USER)'"`
|
||||
Repo string `goptions:"-r, --repo, description='Github repo (required if $GITHUB_REPO not set)'"`
|
||||
Tag string `goptions:"-t, --tag, obligatory, description='Git tag of release to delete'"`
|
||||
} `goptions:"delete"`
|
||||
Info struct {
|
||||
Token string `goptions:"-s, --security-token, description='Github token ($GITHUB_TOKEN if set). required if repo is private.'"`
|
||||
User string `goptions:"-u, --user, description='Github repo user or organisation (required if $GITHUB_USER not set)'"`
|
||||
AuthUser string `goptions:"-a, --auth-user, description='Username for authenticating to the API (falls back to $GITHUB_AUTH_USER or $GITHUB_USER)'"`
|
||||
Repo string `goptions:"-r, --repo, description='Github repo (required if $GITHUB_REPO not set)'"`
|
||||
Tag string `goptions:"-t, --tag, description='Git tag to query (optional)'"`
|
||||
JSON bool `goptions:"-j, --json, description='Emit info as JSON instead of text'"`
|
||||
} `goptions:"info"`
|
||||
}
|
||||
|
||||
type Command func(Options) error
|
||||
|
||||
var commands = map[goptions.Verbs]Command{
|
||||
"download": downloadcmd,
|
||||
"upload": uploadcmd,
|
||||
"release": releasecmd,
|
||||
"edit": editcmd,
|
||||
"delete": deletecmd,
|
||||
"info": infocmd,
|
||||
}
|
||||
|
||||
var (
|
||||
VERBOSITY = 0
|
||||
)
|
||||
|
||||
var (
|
||||
// The user whose token is being used to authenticate to the API. If unset,
|
||||
// EnvUser is used.
|
||||
EnvAuthUser string
|
||||
EnvToken string
|
||||
EnvUser string
|
||||
EnvRepo string
|
||||
EnvApiEndpoint string
|
||||
)
|
||||
|
||||
func init() {
|
||||
EnvToken = os.Getenv("GITHUB_TOKEN")
|
||||
EnvUser = os.Getenv("GITHUB_USER")
|
||||
EnvAuthUser = os.Getenv("GITHUB_AUTH_USER")
|
||||
EnvRepo = os.Getenv("GITHUB_REPO")
|
||||
EnvApiEndpoint = os.Getenv("GITHUB_API")
|
||||
|
||||
if EnvAuthUser == "" {
|
||||
EnvAuthUser = EnvUser
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
options := Options{}
|
||||
|
||||
goptions.ParseAndFail(&options)
|
||||
|
||||
if options.Version {
|
||||
fmt.Printf("github-release v%s\n", github.VERSION)
|
||||
return
|
||||
}
|
||||
|
||||
if len(options.Verbs) == 0 {
|
||||
goptions.PrintHelp()
|
||||
return
|
||||
}
|
||||
|
||||
VERBOSITY = len(options.Verbosity)
|
||||
github.VERBOSITY = VERBOSITY
|
||||
|
||||
if cmd, found := commands[options.Verbs]; found {
|
||||
err := cmd(options)
|
||||
if err != nil {
|
||||
if !options.Quiet {
|
||||
fmt.Fprintln(os.Stderr, "error:", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
12
vendor/github.com/aktau/github-release/release
generated
vendored
Normal file
12
vendor/github.com/aktau/github-release/release
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
main() {
|
||||
apt-get update && apt-get install zip
|
||||
git branch --set-upstream-to=origin/master release
|
||||
set -x
|
||||
exec /bin/bash -c "$@"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
141
vendor/github.com/aktau/github-release/releases.go
generated
vendored
Normal file
141
vendor/github.com/aktau/github-release/releases.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/github-release/github-release/github"
|
||||
"github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
const (
|
||||
RELEASE_LIST_URI = "/repos/%s/%s/releases"
|
||||
RELEASE_LATEST_URI = "/repos/%s/%s/releases/latest"
|
||||
RELEASE_DATE_FORMAT = "02/01/2006 at 15:04"
|
||||
)
|
||||
|
||||
type Release struct {
|
||||
Url string `json:"url"`
|
||||
PageUrl string `json:"html_url"`
|
||||
UploadUrl string `json:"upload_url"`
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"body"`
|
||||
TagName string `json:"tag_name"`
|
||||
Draft bool `json:"draft"`
|
||||
Prerelease bool `json:"prerelease"`
|
||||
Created *time.Time `json:"created_at"`
|
||||
Published *time.Time `json:"published_at"`
|
||||
Assets []Asset `json:"assets"`
|
||||
}
|
||||
|
||||
func (r *Release) CleanUploadUrl() string {
|
||||
bracket := strings.Index(r.UploadUrl, "{")
|
||||
|
||||
if bracket == -1 {
|
||||
return r.UploadUrl
|
||||
}
|
||||
|
||||
return r.UploadUrl[0:bracket]
|
||||
}
|
||||
|
||||
func (r *Release) String() string {
|
||||
str := make([]string, len(r.Assets)+1)
|
||||
str[0] = fmt.Sprintf(
|
||||
"%s, name: '%s', description: '%s', id: %d, tagged: %s, published: %s, draft: %v, prerelease: %v",
|
||||
r.TagName, r.Name, r.Description, r.Id,
|
||||
timeFmtOr(r.Created, RELEASE_DATE_FORMAT, ""),
|
||||
timeFmtOr(r.Published, RELEASE_DATE_FORMAT, ""),
|
||||
Mark(r.Draft), Mark(r.Prerelease))
|
||||
|
||||
for idx, asset := range r.Assets {
|
||||
str[idx+1] = fmt.Sprintf(" - artifact: %s, downloads: %d, state: %s, type: %s, size: %s, id: %d",
|
||||
asset.Name, asset.Downloads, asset.State, asset.ContentType,
|
||||
humanize.Bytes(asset.Size), asset.Id)
|
||||
}
|
||||
|
||||
return strings.Join(str, "\n")
|
||||
}
|
||||
|
||||
type ReleaseCreate struct {
|
||||
TagName string `json:"tag_name"`
|
||||
TargetCommitish string `json:"target_commitish,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Body string `json:"body"`
|
||||
Draft bool `json:"draft"`
|
||||
Prerelease bool `json:"prerelease"`
|
||||
}
|
||||
|
||||
func Releases(user, repo, authUser, token string) ([]Release, error) {
|
||||
var releases []Release
|
||||
client := github.NewClient(authUser, token, nil)
|
||||
client.SetBaseURL(EnvApiEndpoint)
|
||||
err := client.Get(fmt.Sprintf(RELEASE_LIST_URI, user, repo), &releases)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return releases, nil
|
||||
}
|
||||
|
||||
func latestReleaseApi(user, repo, authUser, token string) (*Release, error) {
|
||||
var release Release
|
||||
client := github.NewClient(authUser, token, nil)
|
||||
client.SetBaseURL(EnvApiEndpoint)
|
||||
return &release, client.Get(fmt.Sprintf(RELEASE_LATEST_URI, user, repo), &release)
|
||||
}
|
||||
|
||||
func LatestRelease(user, repo, authUser, token string) (*Release, error) {
|
||||
// If latestReleaseApi DOESN'T give an error, return the release.
|
||||
if latestRelease, err := latestReleaseApi(user, repo, authUser, token); err == nil {
|
||||
return latestRelease, nil
|
||||
}
|
||||
|
||||
// The enterprise api doesnt support the latest release endpoint. Get
|
||||
// all releases and compare the published date to get the latest.
|
||||
releases, err := Releases(user, repo, authUser, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var latestRelIndex = -1
|
||||
maxDate := time.Time{}
|
||||
for i, release := range releases {
|
||||
if relDate := *release.Published; relDate.After(maxDate) {
|
||||
maxDate = relDate
|
||||
latestRelIndex = i
|
||||
}
|
||||
}
|
||||
if latestRelIndex == -1 {
|
||||
return nil, fmt.Errorf("could not find the latest release")
|
||||
}
|
||||
|
||||
vprintln("Scanning ", len(releases), "releases, latest release is", releases[latestRelIndex])
|
||||
return &releases[latestRelIndex], nil
|
||||
}
|
||||
|
||||
func ReleaseOfTag(user, repo, tag, authUser, token string) (*Release, error) {
|
||||
releases, err := Releases(user, repo, authUser, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, release := range releases {
|
||||
if release.TagName == tag {
|
||||
return &release, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not find the release corresponding to tag %s", tag)
|
||||
}
|
||||
|
||||
/* find the release-id of the specified tag */
|
||||
func IdOfTag(user, repo, tag, authUser, token string) (int, error) {
|
||||
release, err := ReleaseOfTag(user, repo, tag, authUser, token)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return release.Id, nil
|
||||
}
|
||||
30
vendor/github.com/aktau/github-release/tags.go
generated
vendored
Normal file
30
vendor/github.com/aktau/github-release/tags.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/github-release/github-release/github"
|
||||
)
|
||||
|
||||
const (
|
||||
TAGS_URI = "/repos/%s/%s/tags"
|
||||
)
|
||||
|
||||
type Tag struct {
|
||||
Name string `json:"name"`
|
||||
Commit Commit `json:"commit"`
|
||||
ZipBallUrl string `json:"zipball_url"`
|
||||
TarBallUrl string `json:"tarball_url"`
|
||||
}
|
||||
|
||||
func (t *Tag) String() string {
|
||||
return t.Name + " (commit: " + t.Commit.Url + ")"
|
||||
}
|
||||
|
||||
// Get the tags associated with a repo.
|
||||
func Tags(user, repo, authUser, token string) ([]Tag, error) {
|
||||
var tags []Tag
|
||||
client := github.NewClient(authUser, token, nil)
|
||||
client.SetBaseURL(EnvApiEndpoint)
|
||||
return tags, client.Get(fmt.Sprintf(TAGS_URI, user, repo), &tags)
|
||||
}
|
||||
9
vendor/github.com/aktau/github-release/term.go
generated
vendored
Normal file
9
vendor/github.com/aktau/github-release/term.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func Mark(ok bool) string {
|
||||
if ok {
|
||||
return "✔"
|
||||
} else {
|
||||
return "✗"
|
||||
}
|
||||
}
|
||||
52
vendor/github.com/aktau/github-release/util.go
generated
vendored
Normal file
52
vendor/github.com/aktau/github-release/util.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
/* nvls returns the first value in xs that is not empty. */
|
||||
func nvls(xs ...string) string {
|
||||
for _, s := range xs {
|
||||
if s != "" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func vprintln(a ...interface{}) (int, error) {
|
||||
if VERBOSITY > 0 {
|
||||
return fmt.Fprintln(os.Stderr, a...)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func vprintf(format string, a ...interface{}) (int, error) {
|
||||
if VERBOSITY > 0 {
|
||||
return fmt.Fprintf(os.Stderr, format, a...)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// formats time `t` as `fmt` if it is not nil, otherwise returns `def`
|
||||
func timeFmtOr(t *time.Time, fmt, def string) string {
|
||||
if t == nil {
|
||||
return def
|
||||
}
|
||||
return t.Format(fmt)
|
||||
}
|
||||
|
||||
// isCharDevice returns true if f is a character device (panics if f can't
|
||||
// be stat'ed).
|
||||
func isCharDevice(f *os.File) bool {
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return (stat.Mode() & os.ModeCharDevice) != 0
|
||||
}
|
||||
1
vendor/github.com/aktau/github-release/version.go
generated
vendored
Normal file
1
vendor/github.com/aktau/github-release/version.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package main
|
||||
15
vendor/github.com/andygrunwald/go-jira/.travis.yml
generated
vendored
15
vendor/github.com/andygrunwald/go-jira/.travis.yml
generated
vendored
@@ -3,15 +3,18 @@ language: go
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- 1.9
|
||||
- "1.9.x"
|
||||
- "1.10.x"
|
||||
- "1.11.x"
|
||||
- "1.12.x"
|
||||
- "1.13.x"
|
||||
|
||||
before_install:
|
||||
- go get -t ./...
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: 1.13.x
|
||||
|
||||
script:
|
||||
- GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
|
||||
|
||||
81
vendor/github.com/andygrunwald/go-jira/CHANGELOG.md
generated
vendored
Normal file
81
vendor/github.com/andygrunwald/go-jira/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [1.12.0](https://github.com/andygrunwald/go-jira/compare/v1.11.1...v1.12.0) (2019-12-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add IssueLinkTypeService with GetList and test ([261889a](https://github.com/andygrunwald/go-jira/commit/261889adc63623fcea0fa8cab0d5da26eec37e68))
|
||||
* add worklog update method ([9ff562a](https://github.com/andygrunwald/go-jira/commit/9ff562ae3ea037961f277be10412ad0a42ff8a6f))
|
||||
* Implement get remote links method ([1946cac](https://github.com/andygrunwald/go-jira/commit/1946cac0fe6ee91f784e3dda3c12f3f30f7115b8))
|
||||
* Implement issue link type DELETE ([e37cc6c](https://github.com/andygrunwald/go-jira/commit/e37cc6c6897830492c070667ab8b68bd85683fc3))
|
||||
* Implement issue link type GET ([57538b9](https://github.com/andygrunwald/go-jira/commit/57538b926c558e97940760a30bdc16cdd37ef4f1))
|
||||
* Implement issue link type POST ([75b9df8](https://github.com/andygrunwald/go-jira/commit/75b9df8b01557f01dc318d33c0bc2841a9c084eb))
|
||||
* Implement issue link type PUT ([48a15c1](https://github.com/andygrunwald/go-jira/commit/48a15c10443a3cff78f0fb2c8034dd772320e238))
|
||||
* provide access to issue transitions loaded from JIRA API ([7530b7c](https://github.com/andygrunwald/go-jira/commit/7530b7cd8266d82cdb4afe831518986772e742ba))
|
||||
|
||||
### [1.11.1](https://github.com/andygrunwald/go-jira/compare/v1.11.0...v1.11.1) (2019-10-17)
|
||||
|
||||
## [1.11.0](https://github.com/andygrunwald/go-jira/compare/v1.10.0...v1.11.0) (2019-10-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add AccountID and AccountType to GroupMember struct ([216e005](https://github.com/andygrunwald/go-jira/commit/216e0056d6385eba9d31cb37e6ff64314860d2cc))
|
||||
* Add AccountType and Locale to User struct ([52ab347](https://github.com/andygrunwald/go-jira/commit/52ab34790307144087f0d9bf86c93a2b2209fe46))
|
||||
* Add GetAllStatuses ([afc96b1](https://github.com/andygrunwald/go-jira/commit/afc96b18d17b77e32cec9e1ac7e4f5dec7e627f5))
|
||||
* Add GetMyFilters to FilterService ([ebae19d](https://github.com/andygrunwald/go-jira/commit/ebae19dda6afd0e54578f30300bc36012381e99b))
|
||||
* Add Search to FilterService ([38a755b](https://github.com/andygrunwald/go-jira/commit/38a755b407cd70d11fe2e2897d814552ca29ab51))
|
||||
* add support for JWT auth with qsh needed by add-ons ([a8bdfed](https://github.com/andygrunwald/go-jira/commit/a8bdfed27ff42a9bb0468b8cf192871780919def))
|
||||
* AddGetBoardConfiguration ([fd698c5](https://github.com/andygrunwald/go-jira/commit/fd698c57163f248f21285d5ebc6a3bb60d46694f))
|
||||
* Replace http.Client with interface for extensibility ([b59a65c](https://github.com/andygrunwald/go-jira/commit/b59a65c365dcefd42e135579e9b7ce9c9c006489))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fix fixversion description tag ([8383e2f](https://github.com/andygrunwald/go-jira/commit/8383e2f5f145d04f6bcdb47fb12a95b58bdcedfa))
|
||||
* Fix typos in filter_test.go ([e9a261c](https://github.com/andygrunwald/go-jira/commit/e9a261c52249073345e5895b22e2cf4d7286497a))
|
||||
|
||||
# [1.10.0](https://github.com/andygrunwald/go-jira/compare/v1.9.0...v1.10.0) (2019-05-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* empty SearchOptions causing malformed request ([b3bf8c2](https://github.com/andygrunwald/go-jira/commit/b3bf8c2))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* added DeleteAttachment ([e93c0e1](https://github.com/andygrunwald/go-jira/commit/e93c0e1))
|
||||
|
||||
|
||||
|
||||
# [1.9.0](https://github.com/andygrunwald/go-jira/compare/v1.8.0...v1.9.0) (2019-05-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **issues:** Added support for AddWorklog and GetWorklogs ([1ebd7e7](https://github.com/andygrunwald/go-jira/commit/1ebd7e7))
|
||||
|
||||
|
||||
|
||||
# [1.8.0](https://github.com/andygrunwald/go-jira/compare/v1.7.0...v1.8.0) (2019-05-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add PriorityService to the main ([8491cb0](https://github.com/andygrunwald/go-jira/commit/8491cb0))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **filter:** Add GetFavouriteList to FilterService. ([645898e](https://github.com/andygrunwald/go-jira/commit/645898e))
|
||||
* Add get all priorities ([1c63e25](https://github.com/andygrunwald/go-jira/commit/1c63e25))
|
||||
* Add ResolutionService to retrieve resolutions ([fb1ce22](https://github.com/andygrunwald/go-jira/commit/fb1ce22))
|
||||
* Add status category constants ([6223ddd](https://github.com/andygrunwald/go-jira/commit/6223ddd))
|
||||
* Add StatusCategory GetList ([049a756](https://github.com/andygrunwald/go-jira/commit/049a756))
|
||||
|
||||
|
||||
|
||||
36
vendor/github.com/andygrunwald/go-jira/Gopkg.lock
generated
vendored
36
vendor/github.com/andygrunwald/go-jira/Gopkg.lock
generated
vendored
@@ -1,36 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fatih/structs"
|
||||
packages = ["."]
|
||||
revision = "a720dfa8df582c51dee1b36feabb906bde1588bd"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/google/go-querystring"
|
||||
packages = ["query"]
|
||||
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/trivago/tgo"
|
||||
packages = [
|
||||
"tcontainer",
|
||||
"treflect"
|
||||
]
|
||||
revision = "e4d1ddd28c17dd89ed26327cf69fded22060671b"
|
||||
version = "v1.0.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "e84ca9eea6d233e0947b0d760913db2983fd4cbf6fd0d8690c737a71affb635c"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
46
vendor/github.com/andygrunwald/go-jira/Gopkg.toml
generated
vendored
46
vendor/github.com/andygrunwald/go-jira/Gopkg.toml
generated
vendored
@@ -1,46 +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
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/fatih/structs"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/google/go-querystring"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/pkg/errors"
|
||||
version = "0.8.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/trivago/tgo"
|
||||
version = "1.0.1"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
15
vendor/github.com/andygrunwald/go-jira/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
15
vendor/github.com/andygrunwald/go-jira/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# PR Description
|
||||
|
||||
_What does this fix or add?_
|
||||
|
||||
# Checklist
|
||||
|
||||
* [ ] Tests added
|
||||
* [ ] Good Path
|
||||
* [ ] Error Path
|
||||
* [ ] Commits follow conventions described here:
|
||||
* [ ] [https://conventionalcommits.org/en/v1.0.0-beta.4/#summary](https://conventionalcommits.org/en/v1.0.0-beta.4/#summary)
|
||||
* [ ] [https://chris.beams.io/posts/git-commit/#seven-rules](https://chris.beams.io/posts/git-commit/#seven-rules)
|
||||
* [ ] Commits are squashed such that
|
||||
* [ ] There is 1 commit per isolated change
|
||||
* [ ] I've not made extraneous commits/changes that are unrelated to my change.
|
||||
76
vendor/github.com/andygrunwald/go-jira/README.md
generated
vendored
76
vendor/github.com/andygrunwald/go-jira/README.md
generated
vendored
@@ -17,15 +17,18 @@
|
||||
|
||||
This package is not JIRA API complete (yet), but you can call every API endpoint you want. See [Call a not implemented API endpoint](#call-a-not-implemented-api-endpoint) how to do this. For all possible API endpoints of JIRA have a look at [latest JIRA REST API documentation](https://docs.atlassian.com/jira/REST/latest/).
|
||||
|
||||
## Compatible JIRA versions
|
||||
## Requirements
|
||||
|
||||
This package was tested against JIRA v6.3.4 and v7.1.2.
|
||||
* Go >= 1.8
|
||||
* JIRA v6.3.4 & v7.1.2.
|
||||
|
||||
## Installation
|
||||
|
||||
It is go gettable
|
||||
|
||||
$ go get github.com/andygrunwald/go-jira
|
||||
```bash
|
||||
go get github.com/andygrunwald/go-jira
|
||||
```
|
||||
|
||||
For stable versions you can use one of our tags with [gopkg.in](http://labix.org/gopkg.in). E.g.
|
||||
|
||||
@@ -40,8 +43,10 @@ import (
|
||||
|
||||
(optional) to run unit / example tests:
|
||||
|
||||
$ cd $GOPATH/src/github.com/andygrunwald/go-jira
|
||||
$ go test -v ./...
|
||||
```bash
|
||||
cd $GOPATH/src/github.com/andygrunwald/go-jira
|
||||
go test -v ./...
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
@@ -89,13 +94,13 @@ For convenience, capability for basic and cookie-based authentication is include
|
||||
|
||||
#### Basic auth example
|
||||
|
||||
A more thorough, [runnable example](examples/basicauth/main.go) is provided in the examples directory.
|
||||
A more thorough, [runnable example](examples/basicauth/main.go) is provided in the examples directory. **It's worth noting that using passwords in basic auth is now deprecated and will be removed.** Jira gives you the ability to [create tokens now.](https://confluence.atlassian.com/cloud/api-tokens-938839638.html)
|
||||
|
||||
```go
|
||||
func main() {
|
||||
tp := jira.BasicAuthTransport{
|
||||
Username: "username",
|
||||
Password: "password",
|
||||
Password: "token",
|
||||
}
|
||||
|
||||
client, err := jira.NewClient(tp.Client(), "https://my.jira.com")
|
||||
@@ -106,25 +111,10 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
#### Authenticate with session cookie
|
||||
#### Authenticate with session cookie [DEPRECATED]
|
||||
|
||||
A more thorough, [runnable example](examples/cookieauth/main.go) is provided in the examples directory.
|
||||
JIRA [deprecated this authentication method.](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-basic-auth-and-cookie-based-auth/) It's not longer available for use.
|
||||
|
||||
Note: The `AuthURL` is almost always going to have the path `/rest/auth/1/session`
|
||||
|
||||
```go
|
||||
tp := jira.CookieAuthTransport{
|
||||
Username: "username",
|
||||
Password: "password",
|
||||
AuthURL: "https://my.jira.com/rest/auth/1/session",
|
||||
}
|
||||
|
||||
client, err := jira.NewClient(tp.Client(), "https://my.jira.com")
|
||||
u, _, err := client.User.Get("admin")
|
||||
|
||||
fmt.Printf("\nEmail: %v\nSuccess!\n", u.EmailAddress)
|
||||
}
|
||||
```
|
||||
|
||||
#### Authenticate with OAuth
|
||||
|
||||
@@ -146,10 +136,9 @@ import (
|
||||
|
||||
func main() {
|
||||
base := "https://my.jira.com"
|
||||
tp := jira.CookieAuthTransport{
|
||||
tp := jira.BasicAuthTransport{
|
||||
Username: "username",
|
||||
Password: "password",
|
||||
AuthURL: fmt.Sprintf("%s/rest/auth/1/session", base),
|
||||
Password: "token",
|
||||
}
|
||||
|
||||
jiraClient, err := jira.NewClient(tp.Client(), base)
|
||||
@@ -200,17 +189,16 @@ import (
|
||||
|
||||
func main() {
|
||||
base := "https://my.jira.com"
|
||||
tp := jira.CookieAuthTransport{
|
||||
tp := jira.BasicAuthTransport{
|
||||
Username: "username",
|
||||
Password: "password",
|
||||
AuthURL: fmt.Sprintf("%s/rest/auth/1/session", base),
|
||||
Password: "token",
|
||||
}
|
||||
|
||||
jiraClient, err := jira.NewClient(tp.Client(), base)
|
||||
req, _ := jiraClient.NewRequest("GET", "/rest/api/2/project", nil)
|
||||
req, _ := jiraClient.NewRequest("GET", "rest/api/2/project", nil)
|
||||
|
||||
projects := new([]jira.Project)
|
||||
_, err := jiraClient.Do(req, projects)
|
||||
_, err = jiraClient.Do(req, projects)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -242,6 +230,8 @@ These services own a responsibility of the single endpoints / usecases of JIRA.
|
||||
|
||||
## Contribution
|
||||
|
||||
We ❤️ PR's
|
||||
|
||||
Contribution, in any kind of way, is highly welcome!
|
||||
It doesn't matter if you are not able to write code.
|
||||
Creating issues or holding talks and help other people to use [go-jira](https://github.com/andygrunwald/go-jira) is contribution, too!
|
||||
@@ -250,15 +240,15 @@ A few examples:
|
||||
* Correct typos in the README / documentation
|
||||
* Reporting bugs
|
||||
* Implement a new feature or endpoint
|
||||
* Sharing the love if [go-jira](https://github.com/andygrunwald/go-jira) and help people to get use to it
|
||||
* Sharing the love of [go-jira](https://github.com/andygrunwald/go-jira) and help people to get use to it
|
||||
|
||||
If you are new to pull requests, checkout [Collaborating on projects using issues and pull requests / Creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
|
||||
|
||||
### Dependency management
|
||||
|
||||
`go-jira` uses `dep` for dependency management. After cloning the repo, it's easy to make sure you have the correct dependencies by running `dep ensure`.
|
||||
`go-jira` uses `go modules` for dependency management. After cloning the repo, it's easy to make sure you have the correct dependencies by running `go mod tidy`.
|
||||
|
||||
For adding new dependencies, updating dependencies, and other operations, the [Daily Dep](https://golang.github.io/dep/docs/daily-dep.html) is a good place to start.
|
||||
For adding new dependencies, updating dependencies, and other operations, the [Daily workflow](https://github.com/golang/go/wiki/Modules#daily-workflow) is a good place to start.
|
||||
|
||||
### Sandbox environment for testing
|
||||
|
||||
@@ -266,6 +256,22 @@ Jira offers sandbox test environments at http://go.atlassian.com/cloud-dev.
|
||||
|
||||
You can read more about them at https://developer.atlassian.com/blog/2016/04/cloud-ecosystem-dev-env/.
|
||||
|
||||
## Releasing
|
||||
|
||||
Install `standard-version`
|
||||
```bash
|
||||
npm i -g standard-version
|
||||
```
|
||||
|
||||
```bash
|
||||
standard-version
|
||||
git push --tags
|
||||
```
|
||||
|
||||
Manually copy/paste text from changelog (for this new version) into the release on Github.com. E.g.
|
||||
|
||||
[https://github.com/andygrunwald/go-jira/releases/edit/v1.11.0](https://github.com/andygrunwald/go-jira/releases/edit/v1.11.0)
|
||||
|
||||
## License
|
||||
|
||||
This project is released under the terms of the [MIT license](http://en.wikipedia.org/wiki/MIT_License).
|
||||
|
||||
127
vendor/github.com/andygrunwald/go-jira/board.go
generated
vendored
127
vendor/github.com/andygrunwald/go-jira/board.go
generated
vendored
@@ -2,6 +2,7 @@ package jira
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -34,7 +35,7 @@ type Board struct {
|
||||
type BoardListOptions struct {
|
||||
// BoardType filters results to boards of the specified type.
|
||||
// Valid values: scrum, kanban.
|
||||
BoardType string `url:"boardType,omitempty"`
|
||||
BoardType string `url:"type,omitempty"`
|
||||
// Name filters results to boards that match or partially match the specified name.
|
||||
Name string `url:"name,omitempty"`
|
||||
// ProjectKeyOrID filters results to boards that are relevant to a project.
|
||||
@@ -44,9 +45,21 @@ type BoardListOptions struct {
|
||||
SearchOptions
|
||||
}
|
||||
|
||||
// Wrapper struct for search result
|
||||
type sprintsResult struct {
|
||||
Sprints []Sprint `json:"values" structs:"values"`
|
||||
// GetAllSprintsOptions specifies the optional parameters to the BoardService.GetList
|
||||
type GetAllSprintsOptions struct {
|
||||
// State filters results to sprints in the specified states, comma-separate list
|
||||
State string `url:"state,omitempty"`
|
||||
|
||||
SearchOptions
|
||||
}
|
||||
|
||||
// SprintsList reflects a list of agile sprints
|
||||
type SprintsList struct {
|
||||
MaxResults int `json:"maxResults" structs:"maxResults"`
|
||||
StartAt int `json:"startAt" structs:"startAt"`
|
||||
Total int `json:"total" structs:"total"`
|
||||
IsLast bool `json:"isLast" structs:"isLast"`
|
||||
Values []Sprint `json:"values" structs:"values"`
|
||||
}
|
||||
|
||||
// Sprint represents a sprint on JIRA agile board
|
||||
@@ -61,12 +74,65 @@ type Sprint struct {
|
||||
State string `json:"state" structs:"state"`
|
||||
}
|
||||
|
||||
// BoardConfiguration represents a boardConfiguration of a jira board
|
||||
type BoardConfiguration struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Self string `json:"self"`
|
||||
Location BoardConfigurationLocation `json:"location"`
|
||||
Filter BoardConfigurationFilter `json:"filter"`
|
||||
SubQuery BoardConfigurationSubQuery `json:"subQuery"`
|
||||
ColumnConfig BoardConfigurationColumnConfig `json:"columnConfig"`
|
||||
}
|
||||
|
||||
// BoardConfigurationFilter reference to the filter used by the given board.
|
||||
type BoardConfigurationFilter struct {
|
||||
ID string `json:"id"`
|
||||
Self string `json:"self"`
|
||||
}
|
||||
|
||||
// BoardConfigurationSubQuery (Kanban only) - JQL subquery used by the given board.
|
||||
type BoardConfigurationSubQuery struct {
|
||||
Query string `json:"query"`
|
||||
}
|
||||
|
||||
// BoardConfigurationLocation reference to the container that the board is located in
|
||||
type BoardConfigurationLocation struct {
|
||||
Type string `json:"type"`
|
||||
Key string `json:"key"`
|
||||
ID string `json:"id"`
|
||||
Self string `json:"self"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// BoardConfigurationColumnConfig lists the columns for a given board in the order defined in the column configuration
|
||||
// with constrainttype (none, issueCount, issueCountExclSubs)
|
||||
type BoardConfigurationColumnConfig struct {
|
||||
Columns []BoardConfigurationColumn `json:"columns"`
|
||||
ConstraintType string `json:"constraintType"`
|
||||
}
|
||||
|
||||
// BoardConfigurationColumn lists the name of the board with the statuses that maps to a particular column
|
||||
type BoardConfigurationColumn struct {
|
||||
Name string `json:"name"`
|
||||
Status []BoardConfigurationColumnStatus `json:"statuses"`
|
||||
}
|
||||
|
||||
// BoardConfigurationColumnStatus represents a status in the column configuration
|
||||
type BoardConfigurationColumnStatus struct {
|
||||
ID string `json:"id"`
|
||||
Self string `json:"self"`
|
||||
}
|
||||
|
||||
// GetAllBoards will returns all boards. This only includes boards that the user has permission to view.
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/board-getAllBoards
|
||||
func (s *BoardService) GetAllBoards(opt *BoardListOptions) (*BoardsList, *Response, error) {
|
||||
apiEndpoint := "rest/agile/1.0/board"
|
||||
url, err := addOptions(apiEndpoint, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := s.client.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -145,22 +211,65 @@ func (s *BoardService) DeleteBoard(boardID int) (*Board, *Response, error) {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
// GetAllSprints will returns all sprints from a board, for a given board Id.
|
||||
// GetAllSprints will return all sprints from a board, for a given board Id.
|
||||
// This only includes sprints that the user has permission to view.
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/board/{boardId}/sprint
|
||||
func (s *BoardService) GetAllSprints(boardID string) ([]Sprint, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/agile/1.0/board/%s/sprint", boardID)
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
id, err := strconv.Atoi(boardID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
result := new(sprintsResult)
|
||||
result, response, err := s.GetAllSprintsWithOptions(id, &GetAllSprintsOptions{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return result.Values, response, nil
|
||||
}
|
||||
|
||||
// GetAllSprintsWithOptions will return sprints from a board, for a given board Id and filtering options
|
||||
// This only includes sprints that the user has permission to view.
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/board/{boardId}/sprint
|
||||
func (s *BoardService) GetAllSprintsWithOptions(boardID int, options *GetAllSprintsOptions) (*SprintsList, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/agile/1.0/board/%d/sprint", boardID)
|
||||
url, err := addOptions(apiEndpoint, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := s.client.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
result := new(SprintsList)
|
||||
resp, err := s.client.Do(req, result)
|
||||
if err != nil {
|
||||
err = NewJiraError(resp, err)
|
||||
}
|
||||
|
||||
return result.Sprints, resp, err
|
||||
return result, resp, err
|
||||
}
|
||||
|
||||
// GetBoardConfiguration will return a board configuration for a given board Id
|
||||
// Jira API docs:https://developer.atlassian.com/cloud/jira/software/rest/#api-rest-agile-1-0-board-boardId-configuration-get
|
||||
func (s *BoardService) GetBoardConfiguration(boardID int) (*BoardConfiguration, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/agile/1.0/board/%d/configuration", boardID)
|
||||
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
result := new(BoardConfiguration)
|
||||
resp, err := s.client.Do(req, result)
|
||||
if err != nil {
|
||||
err = NewJiraError(resp, err)
|
||||
}
|
||||
|
||||
return result, resp, err
|
||||
|
||||
}
|
||||
|
||||
38
vendor/github.com/andygrunwald/go-jira/component.go
generated
vendored
Normal file
38
vendor/github.com/andygrunwald/go-jira/component.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package jira
|
||||
|
||||
// ComponentService handles components for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/software/jira/docs/api/REST/7.10.1/#api/2/component
|
||||
type ComponentService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// CreateComponentOptions are passed to the ComponentService.Create function to create a new JIRA component
|
||||
type CreateComponentOptions struct {
|
||||
Name string `json:"name,omitempty" structs:"name,omitempty"`
|
||||
Description string `json:"description,omitempty" structs:"description,omitempty"`
|
||||
Lead *User `json:"lead,omitempty" structs:"lead,omitempty"`
|
||||
LeadUserName string `json:"leadUserName,omitempty" structs:"leadUserName,omitempty"`
|
||||
AssigneeType string `json:"assigneeType,omitempty" structs:"assigneeType,omitempty"`
|
||||
Assignee *User `json:"assignee,omitempty" structs:"assignee,omitempty"`
|
||||
Project string `json:"project,omitempty" structs:"project,omitempty"`
|
||||
ProjectID int `json:"projectId,omitempty" structs:"projectId,omitempty"`
|
||||
}
|
||||
|
||||
// Create creates a new JIRA component based on the given options.
|
||||
func (s *ComponentService) Create(options *CreateComponentOptions) (*ProjectComponent, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/component"
|
||||
req, err := s.client.NewRequest("POST", apiEndpoint, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
component := new(ProjectComponent)
|
||||
resp, err := s.client.Do(req, component)
|
||||
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
|
||||
return component, resp, nil
|
||||
}
|
||||
18
vendor/github.com/andygrunwald/go-jira/error.go
generated
vendored
18
vendor/github.com/andygrunwald/go-jira/error.go
generated
vendored
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -28,12 +29,19 @@ func NewJiraError(resp *Response, httpError error) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, httpError.Error())
|
||||
}
|
||||
|
||||
jerr := Error{HTTPError: httpError}
|
||||
err = json.Unmarshal(body, &jerr)
|
||||
if err != nil {
|
||||
httpError = errors.Wrap(errors.New("Could not parse JSON"), httpError.Error())
|
||||
return errors.Wrap(err, httpError.Error())
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
if strings.HasPrefix(contentType, "application/json") {
|
||||
err = json.Unmarshal(body, &jerr)
|
||||
if err != nil {
|
||||
httpError = errors.Wrap(errors.New("Could not parse JSON"), httpError.Error())
|
||||
return errors.Wrap(err, httpError.Error())
|
||||
}
|
||||
} else {
|
||||
if httpError == nil {
|
||||
return fmt.Errorf("Got Response Status %s:%s", resp.Status, string(body))
|
||||
}
|
||||
return errors.Wrap(httpError, fmt.Sprintf("%s: %s", resp.Status, string(body)))
|
||||
}
|
||||
|
||||
return &jerr
|
||||
|
||||
43
vendor/github.com/andygrunwald/go-jira/field.go
generated
vendored
Normal file
43
vendor/github.com/andygrunwald/go-jira/field.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package jira
|
||||
|
||||
// FieldService handles fields for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-Field
|
||||
type FieldService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Field represents a field of a JIRA issue.
|
||||
type Field struct {
|
||||
ID string `json:"id,omitempty" structs:"id,omitempty"`
|
||||
Key string `json:"key,omitempty" structs:"key,omitempty"`
|
||||
Name string `json:"name,omitempty" structs:"name,omitempty"`
|
||||
Custom bool `json:"custom,omitempty" structs:"custom,omitempty"`
|
||||
Navigable bool `json:"navigable,omitempty" structs:"navigable,omitempty"`
|
||||
Searchable bool `json:"searchable,omitempty" structs:"searchable,omitempty"`
|
||||
ClauseNames []string `json:"clauseNames,omitempty" structs:"clauseNames,omitempty"`
|
||||
Schema FieldSchema `json:"schema,omitempty" structs:"schema,omitempty"`
|
||||
}
|
||||
|
||||
type FieldSchema struct {
|
||||
Type string `json:"type,omitempty" structs:"type,omitempty"`
|
||||
System string `json:"system,omitempty" structs:"system,omitempty"`
|
||||
}
|
||||
|
||||
// GetList gets all fields from JIRA
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-field-get
|
||||
func (s *FieldService) GetList() ([]Field, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/field"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fieldList := []Field{}
|
||||
resp, err := s.client.Do(req, &fieldList)
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
return fieldList, resp, nil
|
||||
}
|
||||
224
vendor/github.com/andygrunwald/go-jira/filter.go
generated
vendored
Normal file
224
vendor/github.com/andygrunwald/go-jira/filter.go
generated
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
package jira
|
||||
|
||||
import "github.com/google/go-querystring/query"
|
||||
import "fmt"
|
||||
|
||||
// FilterService handles fields for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-group-Filter
|
||||
type FilterService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Filter represents a Filter in Jira
|
||||
type Filter struct {
|
||||
Self string `json:"self"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Owner User `json:"owner"`
|
||||
Jql string `json:"jql"`
|
||||
ViewURL string `json:"viewUrl"`
|
||||
SearchURL string `json:"searchUrl"`
|
||||
Favourite bool `json:"favourite"`
|
||||
FavouritedCount int `json:"favouritedCount"`
|
||||
SharePermissions []interface{} `json:"sharePermissions"`
|
||||
Subscriptions struct {
|
||||
Size int `json:"size"`
|
||||
Items []interface{} `json:"items"`
|
||||
MaxResults int `json:"max-results"`
|
||||
StartIndex int `json:"start-index"`
|
||||
EndIndex int `json:"end-index"`
|
||||
} `json:"subscriptions"`
|
||||
}
|
||||
|
||||
// GetMyFiltersQueryOptions specifies the optional parameters for the Get My Filters method
|
||||
type GetMyFiltersQueryOptions struct {
|
||||
IncludeFavourites bool `url:"includeFavourites,omitempty"`
|
||||
Expand string `url:"expand,omitempty"`
|
||||
}
|
||||
|
||||
// FiltersList reflects a list of filters
|
||||
type FiltersList struct {
|
||||
MaxResults int `json:"maxResults" structs:"maxResults"`
|
||||
StartAt int `json:"startAt" structs:"startAt"`
|
||||
Total int `json:"total" structs:"total"`
|
||||
IsLast bool `json:"isLast" structs:"isLast"`
|
||||
Values []FiltersListItem `json:"values" structs:"values"`
|
||||
}
|
||||
|
||||
// FiltersListItem represents a Filter of FiltersList in Jira
|
||||
type FiltersListItem struct {
|
||||
Self string `json:"self"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Owner User `json:"owner"`
|
||||
Jql string `json:"jql"`
|
||||
ViewURL string `json:"viewUrl"`
|
||||
SearchURL string `json:"searchUrl"`
|
||||
Favourite bool `json:"favourite"`
|
||||
FavouritedCount int `json:"favouritedCount"`
|
||||
SharePermissions []interface{} `json:"sharePermissions"`
|
||||
Subscriptions []struct {
|
||||
ID int `json:"id"`
|
||||
User User `json:"user"`
|
||||
} `json:"subscriptions"`
|
||||
}
|
||||
|
||||
// FilterSearchOptions specifies the optional parameters for the Search method
|
||||
// https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-rest-api-3-filter-search-get
|
||||
type FilterSearchOptions struct {
|
||||
// String used to perform a case-insensitive partial match with name.
|
||||
FilterName string `url:"filterName,omitempty"`
|
||||
|
||||
// User account ID used to return filters with the matching owner.accountId. This parameter cannot be used with owner.
|
||||
AccountID string `url:"accountId,omitempty"`
|
||||
|
||||
// Group name used to returns filters that are shared with a group that matches sharePermissions.group.groupname.
|
||||
GroupName string `url:"groupname,omitempty"`
|
||||
|
||||
// Project ID used to returns filters that are shared with a project that matches sharePermissions.project.id.
|
||||
// Format: int64
|
||||
ProjectID int64 `url:"projectId,omitempty"`
|
||||
|
||||
// Orders the results using one of these filter properties.
|
||||
// - `description` Orders by filter `description`. Note that this ordering works independently of whether the expand to display the description field is in use.
|
||||
// - `favourite_count` Orders by `favouritedCount`.
|
||||
// - `is_favourite` Orders by `favourite`.
|
||||
// - `id` Orders by filter `id`.
|
||||
// - `name` Orders by filter `name`.
|
||||
// - `owner` Orders by `owner.accountId`.
|
||||
//
|
||||
// Default: `name`
|
||||
//
|
||||
// Valid values: id, name, description, owner, favorite_count, is_favorite, -id, -name, -description, -owner, -favorite_count, -is_favorite
|
||||
OrderBy string `url:"orderBy,omitempty"`
|
||||
|
||||
// The index of the first item to return in a page of results (page offset).
|
||||
// Default: 0, Format: int64
|
||||
StartAt int64 `url:"startAt,omitempty"`
|
||||
|
||||
// The maximum number of items to return per page. The maximum is 100.
|
||||
// Default: 50, Format: int32
|
||||
MaxResults int32 `url:"maxResults,omitempty"`
|
||||
|
||||
// Use expand to include additional information about filter in the response. This parameter accepts multiple values separated by a comma:
|
||||
// - description Returns the description of the filter.
|
||||
// - favourite Returns an indicator of whether the user has set the filter as a favorite.
|
||||
// - favouritedCount Returns a count of how many users have set this filter as a favorite.
|
||||
// - jql Returns the JQL query that the filter uses.
|
||||
// - owner Returns the owner of the filter.
|
||||
// - searchUrl Returns a URL to perform the filter's JQL query.
|
||||
// - sharePermissions Returns the share permissions defined for the filter.
|
||||
// - subscriptions Returns the users that are subscribed to the filter.
|
||||
// - viewUrl Returns a URL to view the filter.
|
||||
Expand string `url:"expand,omitempty"`
|
||||
}
|
||||
|
||||
// GetList retrieves all filters from Jira
|
||||
func (fs *FilterService) GetList() ([]*Filter, *Response, error) {
|
||||
|
||||
options := &GetQueryOptions{}
|
||||
apiEndpoint := "rest/api/2/filter"
|
||||
req, err := fs.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if options != nil {
|
||||
q, err := query.Values(options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
filters := []*Filter{}
|
||||
resp, err := fs.client.Do(req, &filters)
|
||||
if err != nil {
|
||||
jerr := NewJiraError(resp, err)
|
||||
return nil, resp, jerr
|
||||
}
|
||||
return filters, resp, err
|
||||
}
|
||||
|
||||
// GetFavouriteList retrieves the user's favourited filters from Jira
|
||||
func (fs *FilterService) GetFavouriteList() ([]*Filter, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/filter/favourite"
|
||||
req, err := fs.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
filters := []*Filter{}
|
||||
resp, err := fs.client.Do(req, &filters)
|
||||
if err != nil {
|
||||
jerr := NewJiraError(resp, err)
|
||||
return nil, resp, jerr
|
||||
}
|
||||
return filters, resp, err
|
||||
}
|
||||
|
||||
// Get retrieves a single Filter from Jira
|
||||
func (fs *FilterService) Get(filterID int) (*Filter, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/api/2/filter/%d", filterID)
|
||||
req, err := fs.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
filter := new(Filter)
|
||||
resp, err := fs.client.Do(req, filter)
|
||||
if err != nil {
|
||||
jerr := NewJiraError(resp, err)
|
||||
return nil, resp, jerr
|
||||
}
|
||||
|
||||
return filter, resp, err
|
||||
}
|
||||
|
||||
// GetMyFilters retrieves the my Filters.
|
||||
//
|
||||
// https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-rest-api-3-filter-my-get
|
||||
func (fs *FilterService) GetMyFilters(opts *GetMyFiltersQueryOptions) ([]*Filter, *Response, error) {
|
||||
apiEndpoint := "rest/api/3/filter/my"
|
||||
url, err := addOptions(apiEndpoint, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := fs.client.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
filters := []*Filter{}
|
||||
resp, err := fs.client.Do(req, &filters)
|
||||
if err != nil {
|
||||
jerr := NewJiraError(resp, err)
|
||||
return nil, resp, jerr
|
||||
}
|
||||
return filters, resp, nil
|
||||
}
|
||||
|
||||
// Search will search for filter according to the search options
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-rest-api-3-filter-search-get
|
||||
func (fs *FilterService) Search(opt *FilterSearchOptions) (*FiltersList, *Response, error) {
|
||||
apiEndpoint := "rest/api/3/filter/search"
|
||||
url, err := addOptions(apiEndpoint, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := fs.client.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
filters := new(FiltersList)
|
||||
resp, err := fs.client.Do(req, filters)
|
||||
if err != nil {
|
||||
jerr := NewJiraError(resp, err)
|
||||
return nil, resp, jerr
|
||||
}
|
||||
|
||||
return filters, resp, err
|
||||
}
|
||||
13
vendor/github.com/andygrunwald/go-jira/go.mod
generated
vendored
Normal file
13
vendor/github.com/andygrunwald/go-jira/go.mod
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
module github.com/andygrunwald/go-jira
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/fatih/structs v1.0.0
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/trivago/tgo v1.0.1
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734
|
||||
)
|
||||
20
vendor/github.com/andygrunwald/go-jira/go.sum
generated
vendored
Normal file
20
vendor/github.com/andygrunwald/go-jira/go.sum
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/fatih/structs v1.0.0 h1:BrX964Rv5uQ3wwS+KRUAJCBBw5PQmgJfJ6v4yly5QwU=
|
||||
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0=
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/trivago/tgo v1.0.1 h1:bxatjJIXNIpV18bucU4Uk/LaoxvxuOlp/oowRHyncLQ=
|
||||
github.com/trivago/tgo v1.0.1/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
5
vendor/github.com/andygrunwald/go-jira/group.go
generated
vendored
5
vendor/github.com/andygrunwald/go-jira/group.go
generated
vendored
@@ -43,12 +43,15 @@ type GroupMember struct {
|
||||
Self string `json:"self,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
AccountID string `json:"accountId,omitempty"`
|
||||
EmailAddress string `json:"emailAddress,omitempty"`
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
Active bool `json:"active,omitempty"`
|
||||
TimeZone string `json:"timeZone,omitempty"`
|
||||
AccountType string `json:"accountType,omitempty"`
|
||||
}
|
||||
|
||||
// GroupSearchOptions specifies the optional parameters for the Get Group methods
|
||||
type GroupSearchOptions struct {
|
||||
StartAt int
|
||||
MaxResults int
|
||||
@@ -78,7 +81,7 @@ func (s *GroupService) Get(name string) ([]GroupMember, *Response, error) {
|
||||
return group.Members, resp, nil
|
||||
}
|
||||
|
||||
// Get returns a paginated list of members of the specified group and its subgroups.
|
||||
// GetWithOptions returns a paginated list of members of the specified group and its subgroups.
|
||||
// Users in the page are ordered by user names.
|
||||
// User of this resource is required to have sysadmin or admin permissions.
|
||||
//
|
||||
|
||||
446
vendor/github.com/andygrunwald/go-jira/issue.go
generated
vendored
446
vendor/github.com/andygrunwald/go-jira/issue.go
generated
vendored
File diff suppressed because it is too large
Load Diff
111
vendor/github.com/andygrunwald/go-jira/issuelinktype.go
generated
vendored
Normal file
111
vendor/github.com/andygrunwald/go-jira/issuelinktype.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
package jira
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// IssueLinkTypeService handles issue link types for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-group-Issue-link-types
|
||||
type IssueLinkTypeService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// GetList gets all of the issue link types from JIRA.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-get
|
||||
func (s *IssueLinkTypeService) GetList() ([]IssueLinkType, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/issueLinkType"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
linkTypeList := []IssueLinkType{}
|
||||
resp, err := s.client.Do(req, &linkTypeList)
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
return linkTypeList, resp, nil
|
||||
}
|
||||
|
||||
// Get gets info of a specific issue link type from JIRA.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-issueLinkTypeId-get
|
||||
func (s *IssueLinkTypeService) Get(ID string) (*IssueLinkType, *Response, error) {
|
||||
apiEndPoint := fmt.Sprintf("rest/api/2/issueLinkType/%s", ID)
|
||||
req, err := s.client.NewRequest("GET", apiEndPoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
linkType := new(IssueLinkType)
|
||||
resp, err := s.client.Do(req, linkType)
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
return linkType, resp, nil
|
||||
}
|
||||
|
||||
// Create creates an issue link type in JIRA.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-post
|
||||
func (s *IssueLinkTypeService) Create(linkType *IssueLinkType) (*IssueLinkType, *Response, error) {
|
||||
apiEndpoint := "/rest/api/2/issueLinkType"
|
||||
req, err := s.client.NewRequest("POST", apiEndpoint, linkType)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, nil)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
responseLinkType := new(IssueLinkType)
|
||||
defer resp.Body.Close()
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
e := fmt.Errorf("Could not read the returned data")
|
||||
return nil, resp, NewJiraError(resp, e)
|
||||
}
|
||||
err = json.Unmarshal(data, responseLinkType)
|
||||
if err != nil {
|
||||
e := fmt.Errorf("Could no unmarshal the data into struct")
|
||||
return nil, resp, NewJiraError(resp, e)
|
||||
}
|
||||
return linkType, resp, nil
|
||||
}
|
||||
|
||||
// Update updates an issue link type. The issue is found by key.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-issueLinkTypeId-put
|
||||
func (s *IssueLinkTypeService) Update(linkType *IssueLinkType) (*IssueLinkType, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/api/2/issueLinkType/%s", linkType.ID)
|
||||
req, err := s.client.NewRequest("PUT", apiEndpoint, linkType)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
resp, err := s.client.Do(req, nil)
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
ret := *linkType
|
||||
return &ret, resp, nil
|
||||
}
|
||||
|
||||
// Delete deletes an issue link type based on provided ID.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issueLinkType-issueLinkTypeId-delete
|
||||
func (s *IssueLinkTypeService) Delete(ID string) (*Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/api/2/issueLinkType/%s", ID)
|
||||
req, err := s.client.NewRequest("DELETE", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, nil)
|
||||
return resp, err
|
||||
}
|
||||
146
vendor/github.com/andygrunwald/go-jira/jira.go
generated
vendored
146
vendor/github.com/andygrunwald/go-jira/jira.go
generated
vendored
@@ -2,38 +2,59 @@ package jira
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// httpClient defines an interface for an http.Client implementation so that alternative
|
||||
// http Clients can be passed in for making requests
|
||||
type httpClient interface {
|
||||
Do(request *http.Request) (response *http.Response, err error)
|
||||
}
|
||||
|
||||
// A Client manages communication with the JIRA API.
|
||||
type Client struct {
|
||||
// HTTP client used to communicate with the API.
|
||||
client *http.Client
|
||||
client httpClient
|
||||
|
||||
// Base URL for API requests.
|
||||
baseURL *url.URL
|
||||
|
||||
// Session storage if the user authentificate with a Session cookie
|
||||
// Session storage if the user authenticates with a Session cookie
|
||||
session *Session
|
||||
|
||||
// Services used for talking to different parts of the JIRA API.
|
||||
Authentication *AuthenticationService
|
||||
Issue *IssueService
|
||||
Project *ProjectService
|
||||
Board *BoardService
|
||||
Sprint *SprintService
|
||||
User *UserService
|
||||
Group *GroupService
|
||||
Version *VersionService
|
||||
Authentication *AuthenticationService
|
||||
Issue *IssueService
|
||||
Project *ProjectService
|
||||
Board *BoardService
|
||||
Sprint *SprintService
|
||||
User *UserService
|
||||
Group *GroupService
|
||||
Version *VersionService
|
||||
Priority *PriorityService
|
||||
Field *FieldService
|
||||
Component *ComponentService
|
||||
Resolution *ResolutionService
|
||||
StatusCategory *StatusCategoryService
|
||||
Filter *FilterService
|
||||
Role *RoleService
|
||||
PermissionScheme *PermissionSchemeService
|
||||
Status *StatusService
|
||||
IssueLinkType *IssueLinkTypeService
|
||||
}
|
||||
|
||||
// NewClient returns a new JIRA API client.
|
||||
@@ -43,11 +64,16 @@ type Client struct {
|
||||
// As an alternative you can use Session Cookie based authentication provided by this package as well.
|
||||
// See https://docs.atlassian.com/jira/REST/latest/#authentication
|
||||
// baseURL is the HTTP endpoint of your JIRA instance and should always be specified with a trailing slash.
|
||||
func NewClient(httpClient *http.Client, baseURL string) (*Client, error) {
|
||||
func NewClient(httpClient httpClient, baseURL string) (*Client, error) {
|
||||
if httpClient == nil {
|
||||
httpClient = http.DefaultClient
|
||||
}
|
||||
|
||||
// ensure the baseURL contains a trailing slash so that all paths are preserved in later calls
|
||||
if !strings.HasSuffix(baseURL, "/") {
|
||||
baseURL += "/"
|
||||
}
|
||||
|
||||
parsedBaseURL, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -65,19 +91,30 @@ func NewClient(httpClient *http.Client, baseURL string) (*Client, error) {
|
||||
c.User = &UserService{client: c}
|
||||
c.Group = &GroupService{client: c}
|
||||
c.Version = &VersionService{client: c}
|
||||
c.Priority = &PriorityService{client: c}
|
||||
c.Field = &FieldService{client: c}
|
||||
c.Component = &ComponentService{client: c}
|
||||
c.Resolution = &ResolutionService{client: c}
|
||||
c.StatusCategory = &StatusCategoryService{client: c}
|
||||
c.Filter = &FilterService{client: c}
|
||||
c.Role = &RoleService{client: c}
|
||||
c.PermissionScheme = &PermissionSchemeService{client: c}
|
||||
c.Status = &StatusService{client: c}
|
||||
c.IssueLinkType = &IssueLinkTypeService{client: c}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewRawRequest creates an API request.
|
||||
// A relative URL can be provided in urlStr, in which case it is resolved relative to the baseURL of the Client.
|
||||
// Relative URLs should always be specified without a preceding slash.
|
||||
// Allows using an optional native io.Reader for sourcing the request body.
|
||||
func (c *Client) NewRawRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
|
||||
rel, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Relative URLs should be specified without a preceding slash since baseURL will have the trailing slash
|
||||
rel.Path = strings.TrimLeft(rel.Path, "/")
|
||||
|
||||
u := c.baseURL.ResolveReference(rel)
|
||||
|
||||
@@ -108,13 +145,14 @@ func (c *Client) NewRawRequest(method, urlStr string, body io.Reader) (*http.Req
|
||||
|
||||
// NewRequest creates an API request.
|
||||
// A relative URL can be provided in urlStr, in which case it is resolved relative to the baseURL of the Client.
|
||||
// Relative URLs should always be specified without a preceding slash.
|
||||
// If specified, the value pointed to by body is JSON encoded and included as the request body.
|
||||
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
|
||||
rel, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Relative URLs should be specified without a preceding slash since baseURL will have the trailing slash
|
||||
rel.Path = strings.TrimLeft(rel.Path, "/")
|
||||
|
||||
u := c.baseURL.ResolveReference(rel)
|
||||
|
||||
@@ -176,13 +214,14 @@ func addOptions(s string, opt interface{}) (string, error) {
|
||||
|
||||
// NewMultiPartRequest creates an API request including a multi-part file.
|
||||
// A relative URL can be provided in urlStr, in which case it is resolved relative to the baseURL of the Client.
|
||||
// Relative URLs should always be specified without a preceding slash.
|
||||
// If specified, the value pointed to by buf is a multipart form.
|
||||
func (c *Client) NewMultiPartRequest(method, urlStr string, buf *bytes.Buffer) (*http.Request, error) {
|
||||
rel, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Relative URLs should be specified without a preceding slash since baseURL will have the trailing slash
|
||||
rel.Path = strings.TrimLeft(rel.Path, "/")
|
||||
|
||||
u := c.baseURL.ResolveReference(rel)
|
||||
|
||||
@@ -327,7 +366,7 @@ func (t *BasicAuthTransport) transport() http.RoundTripper {
|
||||
// CookieAuthTransport is an http.RoundTripper that authenticates all requests
|
||||
// using Jira's cookie-based authentication.
|
||||
//
|
||||
// Note that it is generally preferrable to use HTTP BASIC authentication with the REST API.
|
||||
// Note that it is generally preferable to use HTTP BASIC authentication with the REST API.
|
||||
// However, this resource may be used to mimic the behaviour of JIRA's log-in page (e.g. to display log-in errors to a user).
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#auth/1/session
|
||||
@@ -356,7 +395,10 @@ func (t *CookieAuthTransport) RoundTrip(req *http.Request) (*http.Response, erro
|
||||
|
||||
req2 := cloneRequest(req) // per RoundTripper contract
|
||||
for _, cookie := range t.SessionObject {
|
||||
req2.AddCookie(cookie)
|
||||
// Don't add an empty value cookie to the request
|
||||
if cookie.Value != "" {
|
||||
req2.AddCookie(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
return t.transport().RoundTrip(req2)
|
||||
@@ -417,6 +459,78 @@ func (t *CookieAuthTransport) transport() http.RoundTripper {
|
||||
return http.DefaultTransport
|
||||
}
|
||||
|
||||
// JWTAuthTransport is an http.RoundTripper that authenticates all requests
|
||||
// using Jira's JWT based authentication.
|
||||
//
|
||||
// NOTE: this form of auth should be used by add-ons installed from the Atlassian marketplace.
|
||||
//
|
||||
// JIRA docs: https://developer.atlassian.com/cloud/jira/platform/understanding-jwt
|
||||
// Examples in other languages:
|
||||
// https://bitbucket.org/atlassian/atlassian-jwt-ruby/src/d44a8e7a4649e4f23edaa784402655fda7c816ea/lib/atlassian/jwt.rb
|
||||
// https://bitbucket.org/atlassian/atlassian-jwt-py/src/master/atlassian_jwt/url_utils.py
|
||||
type JWTAuthTransport struct {
|
||||
Secret []byte
|
||||
Issuer string
|
||||
|
||||
// Transport is the underlying HTTP transport to use when making requests.
|
||||
// It will default to http.DefaultTransport if nil.
|
||||
Transport http.RoundTripper
|
||||
}
|
||||
|
||||
func (t *JWTAuthTransport) Client() *http.Client {
|
||||
return &http.Client{Transport: t}
|
||||
}
|
||||
|
||||
func (t *JWTAuthTransport) transport() http.RoundTripper {
|
||||
if t.Transport != nil {
|
||||
return t.Transport
|
||||
}
|
||||
return http.DefaultTransport
|
||||
}
|
||||
|
||||
// RoundTrip adds the session object to the request.
|
||||
func (t *JWTAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req2 := cloneRequest(req) // per RoundTripper contract
|
||||
exp := time.Duration(59) * time.Second
|
||||
qsh := t.createQueryStringHash(req.Method, req2.URL)
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"iss": t.Issuer,
|
||||
"iat": time.Now().Unix(),
|
||||
"exp": time.Now().Add(exp).Unix(),
|
||||
"qsh": qsh,
|
||||
})
|
||||
|
||||
jwtStr, err := token.SignedString(t.Secret)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "jwtAuth: error signing JWT")
|
||||
}
|
||||
|
||||
req2.Header.Set("Authorization", fmt.Sprintf("JWT %s", jwtStr))
|
||||
return t.transport().RoundTrip(req2)
|
||||
}
|
||||
|
||||
func (t *JWTAuthTransport) createQueryStringHash(httpMethod string, jiraURL *url.URL) string {
|
||||
canonicalRequest := t.canonicalizeRequest(httpMethod, jiraURL)
|
||||
h := sha256.Sum256([]byte(canonicalRequest))
|
||||
return hex.EncodeToString(h[:])
|
||||
}
|
||||
|
||||
func (t *JWTAuthTransport) canonicalizeRequest(httpMethod string, jiraURL *url.URL) string {
|
||||
path := "/" + strings.Replace(strings.Trim(jiraURL.Path, "/"), "&", "%26", -1)
|
||||
|
||||
var canonicalQueryString []string
|
||||
for k, v := range jiraURL.Query() {
|
||||
if k == "jwt" {
|
||||
continue
|
||||
}
|
||||
param := url.QueryEscape(k)
|
||||
value := url.QueryEscape(strings.Join(v, ""))
|
||||
canonicalQueryString = append(canonicalQueryString, strings.Replace(strings.Join([]string{param, value}, "="), "+", "%20", -1))
|
||||
}
|
||||
sort.Strings(canonicalQueryString)
|
||||
return fmt.Sprintf("%s&%s&%s", strings.ToUpper(httpMethod), path, strings.Join(canonicalQueryString, "&"))
|
||||
}
|
||||
|
||||
// cloneRequest returns a clone of the provided *http.Request.
|
||||
// The clone is a shallow copy of the struct and its Header map.
|
||||
func cloneRequest(r *http.Request) *http.Request {
|
||||
|
||||
69
vendor/github.com/andygrunwald/go-jira/permissionscheme.go
generated
vendored
Normal file
69
vendor/github.com/andygrunwald/go-jira/permissionscheme.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package jira
|
||||
|
||||
import "fmt"
|
||||
|
||||
// PermissionSchemeService handles permissionschemes for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-group-Permissionscheme
|
||||
type PermissionSchemeService struct {
|
||||
client *Client
|
||||
}
|
||||
type PermissionSchemes struct {
|
||||
PermissionSchemes []PermissionScheme `json:"permissionSchemes" structs:"permissionSchemes"`
|
||||
}
|
||||
|
||||
type Permission struct {
|
||||
ID int `json:"id" structs:"id"`
|
||||
Self string `json:"expand" structs:"expand"`
|
||||
Holder Holder `json:"holder" structs:"holder"`
|
||||
Name string `json:"permission" structs:"permission"`
|
||||
}
|
||||
|
||||
type Holder struct {
|
||||
Type string `json:"type" structs:"type"`
|
||||
Parameter string `json:"parameter" structs:"parameter"`
|
||||
Expand string `json:"expand" structs:"expand"`
|
||||
}
|
||||
|
||||
// GetList returns a list of all permission schemes
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-api-3-permissionscheme-get
|
||||
func (s *PermissionSchemeService) GetList() (*PermissionSchemes, *Response, error) {
|
||||
apiEndpoint := "/rest/api/3/permissionscheme"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pss := new(PermissionSchemes)
|
||||
resp, err := s.client.Do(req, &pss)
|
||||
if err != nil {
|
||||
jerr := NewJiraError(resp, err)
|
||||
return nil, resp, jerr
|
||||
}
|
||||
|
||||
return pss, resp, nil
|
||||
}
|
||||
|
||||
// Get returns a full representation of the permission scheme for the schemeID
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-api-3-permissionscheme-schemeId-get
|
||||
func (s *PermissionSchemeService) Get(schemeID int) (*PermissionScheme, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("/rest/api/3/permissionscheme/%d", schemeID)
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ps := new(PermissionScheme)
|
||||
resp, err := s.client.Do(req, ps)
|
||||
if err != nil {
|
||||
jerr := NewJiraError(resp, err)
|
||||
return nil, resp, jerr
|
||||
}
|
||||
if ps.Self == "" {
|
||||
return nil, resp, fmt.Errorf("No permissionscheme with ID %d found", schemeID)
|
||||
}
|
||||
|
||||
return ps, resp, nil
|
||||
}
|
||||
37
vendor/github.com/andygrunwald/go-jira/priority.go
generated
vendored
Normal file
37
vendor/github.com/andygrunwald/go-jira/priority.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package jira
|
||||
|
||||
// PriorityService handles priorities for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-Priority
|
||||
type PriorityService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Priority represents a priority of a JIRA issue.
|
||||
// Typical types are "Normal", "Moderate", "Urgent", ...
|
||||
type Priority struct {
|
||||
Self string `json:"self,omitempty" structs:"self,omitempty"`
|
||||
IconURL string `json:"iconUrl,omitempty" structs:"iconUrl,omitempty"`
|
||||
Name string `json:"name,omitempty" structs:"name,omitempty"`
|
||||
ID string `json:"id,omitempty" structs:"id,omitempty"`
|
||||
StatusColor string `json:"statusColor,omitempty" structs:"statusColor,omitempty"`
|
||||
Description string `json:"description,omitempty" structs:"description,omitempty"`
|
||||
}
|
||||
|
||||
// GetList gets all priorities from JIRA
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-priority-get
|
||||
func (s *PriorityService) GetList() ([]Priority, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/priority"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
priorityList := []Priority{}
|
||||
resp, err := s.client.Do(req, &priorityList)
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
return priorityList, resp, nil
|
||||
}
|
||||
45
vendor/github.com/andygrunwald/go-jira/project.go
generated
vendored
45
vendor/github.com/andygrunwald/go-jira/project.go
generated
vendored
@@ -36,24 +36,22 @@ type ProjectCategory struct {
|
||||
|
||||
// Project represents a JIRA Project.
|
||||
type Project struct {
|
||||
Expand string `json:"expand,omitempty" structs:"expand,omitempty"`
|
||||
Self string `json:"self,omitempty" structs:"self,omitempty"`
|
||||
ID string `json:"id,omitempty" structs:"id,omitempty"`
|
||||
Key string `json:"key,omitempty" structs:"key,omitempty"`
|
||||
Description string `json:"description,omitempty" structs:"description,omitempty"`
|
||||
Lead User `json:"lead,omitempty" structs:"lead,omitempty"`
|
||||
Components []ProjectComponent `json:"components,omitempty" structs:"components,omitempty"`
|
||||
IssueTypes []IssueType `json:"issueTypes,omitempty" structs:"issueTypes,omitempty"`
|
||||
URL string `json:"url,omitempty" structs:"url,omitempty"`
|
||||
Email string `json:"email,omitempty" structs:"email,omitempty"`
|
||||
AssigneeType string `json:"assigneeType,omitempty" structs:"assigneeType,omitempty"`
|
||||
Versions []Version `json:"versions,omitempty" structs:"versions,omitempty"`
|
||||
Name string `json:"name,omitempty" structs:"name,omitempty"`
|
||||
Roles struct {
|
||||
Developers string `json:"Developers,omitempty" structs:"Developers,omitempty"`
|
||||
} `json:"roles,omitempty" structs:"roles,omitempty"`
|
||||
AvatarUrls AvatarUrls `json:"avatarUrls,omitempty" structs:"avatarUrls,omitempty"`
|
||||
ProjectCategory ProjectCategory `json:"projectCategory,omitempty" structs:"projectCategory,omitempty"`
|
||||
Expand string `json:"expand,omitempty" structs:"expand,omitempty"`
|
||||
Self string `json:"self,omitempty" structs:"self,omitempty"`
|
||||
ID string `json:"id,omitempty" structs:"id,omitempty"`
|
||||
Key string `json:"key,omitempty" structs:"key,omitempty"`
|
||||
Description string `json:"description,omitempty" structs:"description,omitempty"`
|
||||
Lead User `json:"lead,omitempty" structs:"lead,omitempty"`
|
||||
Components []ProjectComponent `json:"components,omitempty" structs:"components,omitempty"`
|
||||
IssueTypes []IssueType `json:"issueTypes,omitempty" structs:"issueTypes,omitempty"`
|
||||
URL string `json:"url,omitempty" structs:"url,omitempty"`
|
||||
Email string `json:"email,omitempty" structs:"email,omitempty"`
|
||||
AssigneeType string `json:"assigneeType,omitempty" structs:"assigneeType,omitempty"`
|
||||
Versions []Version `json:"versions,omitempty" structs:"versions,omitempty"`
|
||||
Name string `json:"name,omitempty" structs:"name,omitempty"`
|
||||
Roles map[string]string `json:"roles,omitempty" structs:"roles,omitempty"`
|
||||
AvatarUrls AvatarUrls `json:"avatarUrls,omitempty" structs:"avatarUrls,omitempty"`
|
||||
ProjectCategory ProjectCategory `json:"projectCategory,omitempty" structs:"projectCategory,omitempty"`
|
||||
}
|
||||
|
||||
// ProjectComponent represents a single component of a project
|
||||
@@ -74,11 +72,12 @@ type ProjectComponent struct {
|
||||
|
||||
// PermissionScheme represents the permission scheme for the project
|
||||
type PermissionScheme struct {
|
||||
Expand string `json:"expand" structs:"expand,omitempty"`
|
||||
Self string `json:"self" structs:"self,omitempty"`
|
||||
ID int `json:"id" structs:"id,omitempty"`
|
||||
Name string `json:"name" structs:"name,omitempty"`
|
||||
Description string `json:"description" structs:"description,omitempty"`
|
||||
Expand string `json:"expand" structs:"expand,omitempty"`
|
||||
Self string `json:"self" structs:"self,omitempty"`
|
||||
ID int `json:"id" structs:"id,omitempty"`
|
||||
Name string `json:"name" structs:"name,omitempty"`
|
||||
Description string `json:"description" structs:"description,omitempty"`
|
||||
Permissions []Permission `json:"permissions" structs:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// GetList gets all projects form JIRA
|
||||
|
||||
35
vendor/github.com/andygrunwald/go-jira/resolution.go
generated
vendored
Normal file
35
vendor/github.com/andygrunwald/go-jira/resolution.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
package jira
|
||||
|
||||
// ResolutionService handles resolutions for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-Resolution
|
||||
type ResolutionService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Resolution represents a resolution of a JIRA issue.
|
||||
// Typical types are "Fixed", "Suspended", "Won't Fix", ...
|
||||
type Resolution struct {
|
||||
Self string `json:"self" structs:"self"`
|
||||
ID string `json:"id" structs:"id"`
|
||||
Description string `json:"description" structs:"description"`
|
||||
Name string `json:"name" structs:"name"`
|
||||
}
|
||||
|
||||
// GetList gets all resolutions from JIRA
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-resolution-get
|
||||
func (s *ResolutionService) GetList() ([]Resolution, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/resolution"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
resolutionList := []Resolution{}
|
||||
resp, err := s.client.Do(req, &resolutionList)
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
return resolutionList, resp, nil
|
||||
}
|
||||
76
vendor/github.com/andygrunwald/go-jira/role.go
generated
vendored
Normal file
76
vendor/github.com/andygrunwald/go-jira/role.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package jira
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// RoleService handles roles for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-group-Role
|
||||
type RoleService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Role represents a JIRA product role
|
||||
type Role struct {
|
||||
Self string `json:"self" structs:"self"`
|
||||
Name string `json:"name" structs:"name"`
|
||||
ID int `json:"id" structs:"id"`
|
||||
Description string `json:"description" structs:"description"`
|
||||
Actors []*Actor `json:"actors" structs:"actors"`
|
||||
}
|
||||
|
||||
// Actor represents a JIRA actor
|
||||
type Actor struct {
|
||||
ID int `json:"id" structs:"id"`
|
||||
DisplayName string `json:"displayName" structs:"displayName"`
|
||||
Type string `json:"type" structs:"type"`
|
||||
Name string `json:"name" structs:"name"`
|
||||
AvatarURL string `json:"avatarUrl" structs:"avatarUrl"`
|
||||
ActorUser *ActorUser `json:"actorUser" structs:"actoruser"`
|
||||
}
|
||||
|
||||
// ActorUser contains the account id of the actor/user
|
||||
type ActorUser struct {
|
||||
AccountID string `json:"accountId" structs:"accountId"`
|
||||
}
|
||||
|
||||
// GetList returns a list of all available project roles
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-api-3-role-get
|
||||
func (s *RoleService) GetList() (*[]Role, *Response, error) {
|
||||
apiEndpoint := "rest/api/3/role"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
roles := new([]Role)
|
||||
resp, err := s.client.Do(req, roles)
|
||||
if err != nil {
|
||||
jerr := NewJiraError(resp, err)
|
||||
return nil, resp, jerr
|
||||
}
|
||||
return roles, resp, err
|
||||
}
|
||||
|
||||
// Get retreives a single Role from Jira
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/#api-api-3-role-id-get
|
||||
func (s *RoleService) Get(roleID int) (*Role, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/api/3/role/%d", roleID)
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
role := new(Role)
|
||||
resp, err := s.client.Do(req, role)
|
||||
if err != nil {
|
||||
jerr := NewJiraError(resp, err)
|
||||
return nil, resp, jerr
|
||||
}
|
||||
if role.Self == "" {
|
||||
return nil, resp, fmt.Errorf("No role with ID %d found", roleID)
|
||||
}
|
||||
|
||||
return role, resp, err
|
||||
}
|
||||
3
vendor/github.com/andygrunwald/go-jira/sprint.go
generated
vendored
3
vendor/github.com/andygrunwald/go-jira/sprint.go
generated
vendored
@@ -2,6 +2,7 @@ package jira
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
@@ -67,7 +68,7 @@ func (s *SprintService) GetIssuesForSprint(sprintID int) ([]Issue, *Response, er
|
||||
return result.Issues, resp, err
|
||||
}
|
||||
|
||||
// Get returns a full representation of the issue for the given issue key.
|
||||
// GetIssue returns a full representation of the issue for the given issue key.
|
||||
// JIRA will attempt to identify the issue by the issueIdOrKey path parameter.
|
||||
// This can be an issue id, or an issue key.
|
||||
// If the issue cannot be found via an exact match, JIRA will also look for the issue in a case-insensitive way, or by looking to see if the issue was moved.
|
||||
|
||||
40
vendor/github.com/andygrunwald/go-jira/status.go
generated
vendored
Normal file
40
vendor/github.com/andygrunwald/go-jira/status.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package jira
|
||||
|
||||
// StatusService handles staties for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-group-Workflow-statuses
|
||||
type StatusService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Status represents the current status of a JIRA issue.
|
||||
// Typical status are "Open", "In Progress", "Closed", ...
|
||||
// Status can be user defined in every JIRA instance.
|
||||
type Status struct {
|
||||
Self string `json:"self" structs:"self"`
|
||||
Description string `json:"description" structs:"description"`
|
||||
IconURL string `json:"iconUrl" structs:"iconUrl"`
|
||||
Name string `json:"name" structs:"name"`
|
||||
ID string `json:"id" structs:"id"`
|
||||
StatusCategory StatusCategory `json:"statusCategory" structs:"statusCategory"`
|
||||
}
|
||||
|
||||
// GetAllStatuses returns a list of all statuses associated with workflows.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-status-get
|
||||
func (s *StatusService) GetAllStatuses() ([]Status, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/status"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
statusList := []Status{}
|
||||
resp, err := s.client.Do(req, &statusList)
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
|
||||
return statusList, resp, nil
|
||||
}
|
||||
44
vendor/github.com/andygrunwald/go-jira/statuscategory.go
generated
vendored
Normal file
44
vendor/github.com/andygrunwald/go-jira/statuscategory.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package jira
|
||||
|
||||
// StatusCategoryService handles status categories for the JIRA instance / API.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-Statuscategory
|
||||
type StatusCategoryService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// StatusCategory represents the category a status belongs to.
|
||||
// Those categories can be user defined in every JIRA instance.
|
||||
type StatusCategory struct {
|
||||
Self string `json:"self" structs:"self"`
|
||||
ID int `json:"id" structs:"id"`
|
||||
Name string `json:"name" structs:"name"`
|
||||
Key string `json:"key" structs:"key"`
|
||||
ColorName string `json:"colorName" structs:"colorName"`
|
||||
}
|
||||
|
||||
// These constants are the keys of the default JIRA status categories
|
||||
const (
|
||||
StatusCategoryComplete = "done"
|
||||
StatusCategoryInProgress = "indeterminate"
|
||||
StatusCategoryToDo = "new"
|
||||
StatusCategoryUndefined = "undefined"
|
||||
)
|
||||
|
||||
// GetList gets all status categories from JIRA
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-statuscategory-get
|
||||
func (s *StatusCategoryService) GetList() ([]StatusCategory, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/statuscategory"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
statusCategoryList := []StatusCategory{}
|
||||
resp, err := s.client.Do(req, &statusCategoryList)
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
return statusCategoryList, resp, nil
|
||||
}
|
||||
104
vendor/github.com/andygrunwald/go-jira/user.go
generated
vendored
104
vendor/github.com/andygrunwald/go-jira/user.go
generated
vendored
@@ -15,15 +15,20 @@ type UserService struct {
|
||||
|
||||
// User represents a JIRA user.
|
||||
type User struct {
|
||||
Self string `json:"self,omitempty" structs:"self,omitempty"`
|
||||
Self string `json:"self,omitempty" structs:"self,omitempty"`
|
||||
AccountID string `json:"accountId,omitempty" structs:"accountId,omitempty"`
|
||||
AccountType string `json:"accountType,omitempty" structs:"accountType,omitempty"`
|
||||
// TODO: name & key are deprecated, see:
|
||||
// https://developer.atlassian.com/cloud/jira/platform/api-changes-for-user-privacy-announcement/
|
||||
Name string `json:"name,omitempty" structs:"name,omitempty"`
|
||||
Password string `json:"-"`
|
||||
Key string `json:"key,omitempty" structs:"key,omitempty"`
|
||||
Password string `json:"-"`
|
||||
EmailAddress string `json:"emailAddress,omitempty" structs:"emailAddress,omitempty"`
|
||||
AvatarUrls AvatarUrls `json:"avatarUrls,omitempty" structs:"avatarUrls,omitempty"`
|
||||
DisplayName string `json:"displayName,omitempty" structs:"displayName,omitempty"`
|
||||
Active bool `json:"active,omitempty" structs:"active,omitempty"`
|
||||
TimeZone string `json:"timeZone,omitempty" structs:"timeZone,omitempty"`
|
||||
Locale string `json:"locale,omitempty" structs:"locale,omitempty"`
|
||||
ApplicationKeys []string `json:"applicationKeys,omitempty" structs:"applicationKeys,omitempty"`
|
||||
}
|
||||
|
||||
@@ -33,6 +38,15 @@ type UserGroup struct {
|
||||
Name string `json:"name,omitempty" structs:"name,omitempty"`
|
||||
}
|
||||
|
||||
type userSearchParam struct {
|
||||
name string
|
||||
value string
|
||||
}
|
||||
|
||||
type userSearch []userSearchParam
|
||||
|
||||
type userSearchF func(userSearch) userSearch
|
||||
|
||||
// Get gets user info from JIRA
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/user-getUser
|
||||
@@ -81,6 +95,24 @@ func (s *UserService) Create(user *User) (*User, *Response, error) {
|
||||
return responseUser, resp, nil
|
||||
}
|
||||
|
||||
// Delete deletes an user from JIRA.
|
||||
// Returns http.StatusNoContent on success.
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-user-delete
|
||||
func (s *UserService) Delete(username string) (*Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("/rest/api/2/user?username=%s", username)
|
||||
req, err := s.client.NewRequest("DELETE", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, nil)
|
||||
if err != nil {
|
||||
return resp, NewJiraError(resp, err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetGroups returns the groups which the user belongs to
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/user-getUserGroups
|
||||
@@ -99,12 +131,76 @@ func (s *UserService) GetGroups(username string) (*[]UserGroup, *Response, error
|
||||
return userGroups, resp, nil
|
||||
}
|
||||
|
||||
// Get information about the current logged-in user
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-myself-get
|
||||
func (s *UserService) GetSelf() (*User, *Response, error) {
|
||||
const apiEndpoint = "rest/api/2/myself"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var user User
|
||||
resp, err := s.client.Do(req, &user)
|
||||
if err != nil {
|
||||
return nil, resp, NewJiraError(resp, err)
|
||||
}
|
||||
return &user, resp, nil
|
||||
}
|
||||
|
||||
// WithMaxResults sets the max results to return
|
||||
func WithMaxResults(maxResults int) userSearchF {
|
||||
return func(s userSearch) userSearch {
|
||||
s = append(s, userSearchParam{name: "maxResults", value: fmt.Sprintf("%d", maxResults)})
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
// WithStartAt set the start pager
|
||||
func WithStartAt(startAt int) userSearchF {
|
||||
return func(s userSearch) userSearch {
|
||||
s = append(s, userSearchParam{name: "startAt", value: fmt.Sprintf("%d", startAt)})
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
// WithActive sets the active users lookup
|
||||
func WithActive(active bool) userSearchF {
|
||||
return func(s userSearch) userSearch {
|
||||
s = append(s, userSearchParam{name: "includeActive", value: fmt.Sprintf("%t", active)})
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
// WithInactive sets the inactive users lookup
|
||||
func WithInactive(inactive bool) userSearchF {
|
||||
return func(s userSearch) userSearch {
|
||||
s = append(s, userSearchParam{name: "includeInactive", value: fmt.Sprintf("%t", inactive)})
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
// Find searches for user info from JIRA:
|
||||
// It can find users by email, username or name
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/cloud/#api/2/user-findUsers
|
||||
func (s *UserService) Find(property string) ([]User, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("/rest/api/2/user/search?username=%s", property)
|
||||
func (s *UserService) Find(property string, tweaks ...userSearchF) ([]User, *Response, error) {
|
||||
search := []userSearchParam{
|
||||
{
|
||||
name: "username",
|
||||
value: property,
|
||||
},
|
||||
}
|
||||
for _, f := range tweaks {
|
||||
search = f(search)
|
||||
}
|
||||
|
||||
var queryString = ""
|
||||
for _, param := range search {
|
||||
queryString += param.name + "=" + param.value + "&"
|
||||
}
|
||||
|
||||
apiEndpoint := fmt.Sprintf("/rest/api/2/user/search?%s", queryString[:len(queryString)-1])
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
3
vendor/github.com/andygrunwald/go-jira/version.go
generated
vendored
3
vendor/github.com/andygrunwald/go-jira/version.go
generated
vendored
@@ -18,12 +18,13 @@ type Version struct {
|
||||
Self string `json:"self,omitempty" structs:"self,omitempty"`
|
||||
ID string `json:"id,omitempty" structs:"id,omitempty"`
|
||||
Name string `json:"name,omitempty" structs:"name,omitempty"`
|
||||
Description string `json:"description,omitempty" structs:"name,omitempty"`
|
||||
Description string `json:"description,omitempty" structs:"description,omitempty"`
|
||||
Archived bool `json:"archived,omitempty" structs:"archived,omitempty"`
|
||||
Released bool `json:"released,omitempty" structs:"released,omitempty"`
|
||||
ReleaseDate string `json:"releaseDate,omitempty" structs:"releaseDate,omitempty"`
|
||||
UserReleaseDate string `json:"userReleaseDate,omitempty" structs:"userReleaseDate,omitempty"`
|
||||
ProjectID int `json:"projectId,omitempty" structs:"projectId,omitempty"` // Unlike other IDs, this is returned as a number
|
||||
StartDate string `json:"startDate,omitempty" structs:"startDate,omitempty"`
|
||||
}
|
||||
|
||||
// Get gets version info from JIRA
|
||||
|
||||
2
vendor/github.com/chzyer/readline/complete.go
generated
vendored
2
vendor/github.com/chzyer/readline/complete.go
generated
vendored
@@ -221,7 +221,7 @@ func (o *opCompleter) CompleteRefresh() {
|
||||
}
|
||||
buf.WriteString(string(same))
|
||||
buf.WriteString(string(c))
|
||||
buf.Write(bytes.Repeat([]byte(" "), colWidth-len(c)-len(same)))
|
||||
buf.Write(bytes.Repeat([]byte(" "), colWidth-runes.WidthAll(c)-runes.WidthAll(same)))
|
||||
|
||||
if inSelect {
|
||||
buf.WriteString("\033[0m")
|
||||
|
||||
3
vendor/github.com/containous/go-bindata/.gitignore
generated
vendored
Normal file
3
vendor/github.com/containous/go-bindata/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.idea/
|
||||
vendor/
|
||||
dist/
|
||||
18
vendor/github.com/containous/go-bindata/.travis.yml
generated
vendored
Normal file
18
vendor/github.com/containous/go-bindata/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.x
|
||||
|
||||
install:
|
||||
- echo "TRAVIS_GO_VERSION=$TRAVIS_GO_VERSION"
|
||||
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key: ${GITHUB_TOKEN}
|
||||
file: dist/go-bindata
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
file_glob: true
|
||||
on:
|
||||
tags: true
|
||||
condition: $TRAVIS_GO_VERSION =~ ^1\.x$
|
||||
79
vendor/github.com/containous/go-bindata/CONTRIBUTING.md
generated
vendored
Normal file
79
vendor/github.com/containous/go-bindata/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
## Contribution guidelines.
|
||||
|
||||
So you wish to contribute to this project? Fantastic!
|
||||
Here are a few guidelines to help you do this in a
|
||||
streamlined fashion.
|
||||
|
||||
|
||||
## Bug reports
|
||||
|
||||
When supplying a bug report, please consider the following guidelines.
|
||||
These serve to make it easier for us to address the issue and find a solution.
|
||||
Most of these are pretty self-evident, but sometimes it is still necessary
|
||||
to reiterate them.
|
||||
|
||||
* Be clear in the way you express the problem. Use simple language and
|
||||
just enough of it to clearly define the issue. Not everyone is a native
|
||||
English speaker. And while most can handle themselves pretty well,
|
||||
it helps to stay away from more esoteric vocabulary.
|
||||
|
||||
Be patient with non-native English speakers. If their bug reports
|
||||
or comments are hard to understand, just ask for clarification.
|
||||
Do not start guessing at their meaning, as this may just lead to
|
||||
more confusion and misunderstandings.
|
||||
* Clearly define any information which is relevant to the problem.
|
||||
This includes library versions, operating system and any other
|
||||
external dependencies which may be needed.
|
||||
* Where applicable, provide a step-by-step listing of the way to
|
||||
reproduce the problem. Make sure this is the simplest possible
|
||||
way to do so. Omit any and all unneccesary steps, because they may
|
||||
just complicate our understanding of the real problem.
|
||||
If need be, create a whole new code project on your local machine,
|
||||
which specifically tries to create the problem you are running into;
|
||||
nothing more, nothing less.
|
||||
|
||||
Include this program in the bug report. It often suffices to paste
|
||||
the code in a [Gist](https://gist.github.com) or on the
|
||||
[Go playground](http://play.golang.org).
|
||||
* If possible, provide us with a listing of the steps you have already
|
||||
undertaken to solve the problem. This can save us a great deal of
|
||||
wasted time, trying out solutions you have already covered.
|
||||
|
||||
|
||||
## Pull requests
|
||||
|
||||
Bug reports are great. Supplying fixes to bugs is even better.
|
||||
When submitting a pull request, the following guidelines are
|
||||
good to keep in mind:
|
||||
|
||||
* `go fmt`: **Always** run your code through `go fmt`, before
|
||||
committing it. Code has to be readable by many different
|
||||
people. And the only way this will be as painless as possible,
|
||||
is if we all stick to the same code style.
|
||||
|
||||
Some of our projects may have automated build-servers hooked up
|
||||
to commit hooks. These will vet any submitted code and determine
|
||||
if it meets a set of properties. One of which is code formatting.
|
||||
These servers will outright deny a submission which has not been
|
||||
run through `go fmt`, even if the code itself is correct.
|
||||
|
||||
We try to maintain a zero-tolerance policy on this matter,
|
||||
because consistently formatted code makes life a great deal
|
||||
easier for everyone involved.
|
||||
* Commit log messages: When committing changes, do so often and
|
||||
clearly -- Even if you have changed only 1 character in a code
|
||||
comment. This means that commit log messages should clearly state
|
||||
exactly what the change does and why. If it fixes a known issue,
|
||||
then mention the issue number in the commit log. E.g.:
|
||||
|
||||
> Fixes return value for `foo/boo.Baz()` to be consistent with
|
||||
> the rest of the API. This addresses issue #32
|
||||
|
||||
Do not pile a lot of unrelated changes into a single commit.
|
||||
Pick and choose only those changes for a single commit, which are
|
||||
directly related. We would much rather see a hundred commits
|
||||
saying nothing but `"Runs go fmt"` in between any real fixes
|
||||
than have these style changes embedded in those real fixes.
|
||||
It creates a lot of noise when trying to review code.
|
||||
|
||||
|
||||
3
vendor/github.com/containous/go-bindata/LICENSE
generated
vendored
Normal file
3
vendor/github.com/containous/go-bindata/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
license. Its contents can be found at:
|
||||
http://creativecommons.org/publicdomain/zero/1.0
|
||||
31
vendor/github.com/containous/go-bindata/Makefile
generated
vendored
Normal file
31
vendor/github.com/containous/go-bindata/Makefile
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
.PHONY: all clean checks test build image dependencies
|
||||
|
||||
SRCS = $(shell git ls-files '*.go' | grep -v '^vendor/')
|
||||
|
||||
MAIN_DIRECTORY := ./go-bindata/
|
||||
BIN_OUTPUT := dist/go-bindata
|
||||
|
||||
TAG_NAME := $(shell git tag -l --contains HEAD)
|
||||
SHA := $(shell git rev-parse HEAD)
|
||||
VERSION := $(if $(TAG_NAME),$(TAG_NAME),$(SHA))
|
||||
|
||||
default: clean test build
|
||||
|
||||
clean:
|
||||
rm -rf dist/ builds/ cover.out
|
||||
|
||||
build: clean
|
||||
@echo Version: $(VERSION)
|
||||
go build -v -ldflags '-X "main.AppVersion=${VERSION}"' -o ${BIN_OUTPUT} ${MAIN_DIRECTORY}
|
||||
|
||||
dependencies:
|
||||
dep ensure -v
|
||||
|
||||
test: clean
|
||||
go test -v -cover ./...
|
||||
|
||||
testdata:
|
||||
make -C testdata
|
||||
|
||||
fmt:
|
||||
gofmt -s -l -w $(SRCS)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user