# Developing ## Contents - [Developing](#developing) - [Contents](#contents) - [Building](#building) - [Testing](#testing) - [Messaging](#messaging) - [Friendly Types](#friendly-types) - [TODOs](#todos) - [Features](#features) - [Questions](#questions) ## Building 1. Clone with `git clone git@github.com:ssube/deploy-lock.git` 2. Switch into the project directory with `cd deploy-lock` 3. Run a full lint, build, and test with `make ci` 4. Run the program's help with `make run-help` or `node out/src/index.js --help` ## Testing You can test locally without a real DDB table using https://hub.docker.com/r/amazon/dynamodb-local. 1. Launch DynamoDB Local with `podman run --rm -p 8000:8000 docker.io/amazon/dynamodb-local` 2. Create a profile with `aws configure --profile localddb` 1. placeholder tokens 2. us-east-1 region 3. json output 3. Create a `locks` table with `aws dynamodb --endpoint-url http://localhost:8000 --profile localddb create-table --attribute-definitions 'AttributeName=path,AttributeType=S' --table-name locks --key-schema 'AttributeName=path,KeyType=HASH' --billing-mode PAY_PER_REQUEST` 4. Run commands using `AWS_PROFILE=localddb deploy-lock --storage dynamo --table locks --endpoint http://localhost:8000 ...` ## Messaging - create a new lock: `locked ${path} for ${type:friendly} until ${expires_at:datetime}` - > Locked `apps/acceptance/a` for a deploy until Sat 31 Dec, 12:00 - > Locked `gitlab/production` for an incident until Sat 31 Dec, 12:00 - error, existing lock: `error: ${path} is locked until ${expires_at:datetime} by ${type:friendly} in ${source}` - > Error: `apps/acceptance` is locked until Sat 31 Dec, 12:00 by an automation run in `testing/staging`. ### Friendly Types Friendly strings for `type`: - `automation`: `An automation run` - `deploy`: `A deploy` - `freeze`: `A release freeze` - `incident`: `An incident` - `maintenance`: `A maintenance window` ## TODOs ### Features 1. Infer lock source from arguments/environment, like `CI_` variables 2. SQL data store, with history (don't need to remove old records) 3. S3 data store 4. Kubernetes admission controller with configurable paths Other potential data stores could include: flat file, kubernetes configmap, etcd itself, consul, redis. ### Questions 1. In the [deploy path](../READMDE.md#deploy-path), should account come before region or region before account? 1. `aws/us-east-1/staging` vs `aws/staging/us-east-1` 2. This is purely a recommendation in the docs, `lock.path` and `lock.source` will both be slash-delimited or array paths. 2. Should there be an `update` or `replace` command? 1. Probably not, at least not without lock history or multi-party locks. 2. When the data store can keep old locks, `replace` could expire an existing lock and create a new one 3. With multi-party locks, `update` could update the `expires_at` and add a new author 3. Should `--recursive` be available for `lock` and `unlock`, or only `check`? 1. TBD 2. A recursive `lock` would write multiple records 3. A recursive `unlock` could delete multiple records 4. Should locks have multiple authors? 1. TBD 2. It doesn't make sense to have more than one active lock for the same path 1. Or does it? 2. Different levels can use `--allow` without creating multiple locks 3. But having multiple authors would allow for multi-party locks 1. for CI: `[gitlab, $GITLAB_USER_NAME]` 2. for an incident: `[first-responder, incident-commander]` 4. Each author has to `unlock` before the lock is removed/released 5. Should `LockData.env` be a string/array, like `LockData.path`? 1. Done 2. Very probably yes, because otherwise it will need `env.cloud`, `env.network`, etc, and those are not always predictable/present. 6. Should there be an `--allow`/`LockData.allow` field? 1. Probably yes 2. When running `check --type`, if `LockData.allow` includes `--type`, it will be allowed 1. `freeze` should allow `automation`, but not `deploy` 2. `incident` could allow `deploy`, but not `automation` 7. Wildcards in paths? 1. Probably no, it will become confusing pretty quickly, and KV stores do not support them consistently (or at all). 8. Authz for API mutations? 1. If there is a REST API, it might need authn/authz. 2. Keeping the API private _could_ work. 3. Authorization should be scoped by path. 9. How should the `AdmissionReview` fields be mapped to path? 1. This could vary by user and may need to be configurable. 2. Probably using an argument, `--admission-path` 3. Will eventually need to use jsonpath for access to `userInfo.groups` list or maps