For general contribution and community guidelines, please see the community repo. In particular, before contributing please review our contributor licensing guide to ensure your contribution is compliant with our contributor license agreements.
- Prerequisites
- Pull Request Workflow
- Style Guide
- Building
- Testing
- Documentation
- Profiling
- Plugins
- Submodules
- Releasing
To work in this codebase, you will want to have at least Go 1.22 installed.
Due to a dependency on k8s/client-go
, our project requires that you have
installed Mercurial (hg
on the CLI) on your system.
macOS:
brew install mercurial
Linux:
# Alpine
apk add -u mercurial
# Debian-based
apt update
apt install mercurial
- Search the open issues in GitHub to find out what has been planned
- Select an existing issue or open an issue to propose changes or fixes
- Add the
implementing
label to the issue as you begin to work on it - Run tests as described here, ensuring they pass
- Submit a pull request, linking the issue in the description (e.g.
Connected to #123
) - Add the
implemented
label to the issue, and ask another contributor to review and merge your code
In addition to technical workflow descriptions available in GitHub, some of the project's technical design documents can be found in the project design folder.
Use this guide to maintain consistent style across the Secretless Broker project.
First, clone https://github.com/cyberark/secretless-broker
with the
--recurse-submodules
flag. If you already have secretless-broker cloned locally,
but are missing submodules, perform git submodule update --init --recursive
.
If you're new to Go, be aware that Go can be very selective about where the files
are placed on the filesystem. There is an environment variable called GOPATH
,
whose default value is ~/go
. Secretless Broker uses
go modules
which require either that you clone this repository outside of your GOPATH
or
you set the GO111MODULE
environment variable to on
. We recommend cloning this
repository outside of your GOPATH
.
Once you've cloned the repository, you can build the Secretless Broker.
Note: On git submodules, taken from git documentation.
Luckily, you can tell Git (>=2.14) to always use the --recurse-submodules flag by setting the configuration option submodule.recurse: git config submodule.recurse true. As noted above, this will also make Git recurse into submodules for every command that has a --recurse-submodules option (except git clone)
In most of our build scripts we provide a static (compile-time) version augmentation so that
the final artifacts include the Git short-hash of the code used to build it so that it looks
similar to: <sem_ver>-<git_short_hash>
. We do this in most cases by over-riding the Tag
variable value in pkg/secretless
package with ldflags in this manner:
...
-ldflags="-X github.com/cyberark/secretless-broker/pkg/secretless.Tag=<git_short_hash>"
...
If you would like the same behavior and something other than the default dev
tag, you will
need to add the same ldflags to your build commands or rely on the current build scripts to
create your final deliverable.
# From Secretless Broker repository root
./bin/build
This should create a Docker container with tag secretless-broker:latest
in your local registry.
# From Secretless Broker repository root
go build -o ./secretless-broker ./cmd/secretless-broker
# From Secretless Broker repository root
./bin/build_darwin
- Docker You need Docker to run the tests.
Build the project by running:
./bin/build
Then run the test cases:
./bin/test
Each integration test exists in its own subdirectory within the "test" directory. The test runner assumes it has the following executable scripts, which will be run in order:
./start
(required) - Performs setup work -- eg, spinning up test containers, populating a database with test data, etc../test
(required) - Runs the actual tests. It is assumed to produce go test output on stdout../stop
(optional) - Performs cleanup work.
To add a new integration test, complete the following two steps:
- Create a folder with test scripts as described above.
- Jenkins will automatically search the
test
directory for any sub-directories that meet the criteria of having both astart
andstop
script. It then runs the./bin/run_integration
script on that directory.
Note: You can test locally using the same format of ./bin/run_integration <test directory name>
. You can pass in the name of the directory itself, you don't need the
full path.
If you are on a Mac, you may also test the Mac OS Keychain provider:
cd test/providers/keychain/
./start
./test
This test will not be run as part of the test suite, since it requires access to the Mac OSX Keychain. You will be prompted for your password when running this test, as it temporarily adds a generic password to your account, and verifies that it can retrieve the value.
cd test/manual/k8s_crds
./deploy
This test currently does not run as part of the test suite.
We use Code Climate in our CI pipeline to perform linting and other style
checks. The specific engines we use and their configuration is in
.codeclimate.yml
.
To run linting checks via the Code Climate golint engine, simply run:
./bin/check_style
We use gosec to perform static analysis of our codebase in our CI for all changed code. To run gosec locally for the entire repository, simply run:
go install github.com/securego/gosec/v2/cmd/gosec@latest
$(go env GOPATH)/bin/gosec ./...
For instructions on how to test individual connectors, see the README.md file in the connector's test directory, eg: test/connector/tcp/mysql/README.md.
Secretless has a few sources for documentation: a website, a documentation subdomain, and godocs.
The website source is in the docs folder in this repository. It is generated using Jekyll.
The source includes:
- the website main page
- some old pages that redirect to the documentation subdomain
- tutorials
- godocs for the plugin API
- Secretless blog
- community info page
To get the site up and running locally on your computer, ensure you have:
- Ruby version 3.0.0 or higher (check by running
ruby -v
) - Bundler (
gem install bundler
) - Jekyll (
gem install jekyll
) - Once Bundler and Jekyll gems are installed, run
bundle install
To construct:
git clone https://github.com/cyberark/secretless-broker
cd docs
- Run the following command:
bundle exec jekyll serve
- Preview Jekyll site locally in web browser by either running
open localhost:4000
or manually navigating to http://localhost:4000
With docker
and docker compose
:
- Run
docker compose up -d
in thedocs
directory. - Preview Jekyll site locally in web browser by either running
open localhost:4000
or manually navigating to http://localhost:4000
The documentation website source is in the secretless-docs repo; instructions for contributing are available there.
Godocs are auto-published, and our ./bin/build_website
script also generates godocs for our plugin API that are published to our website.
Profiling can be used to monitor the impact of Secretless on CPU and Memory consumption. Currently, Secretless supports two types - CPU and Memory.
Prerequisites:
- Graphviz to visualize profiling results
- Postgresql to install Postgres
We've provided sample instructions below for profiling the PostgreSQL handler.
Note: If you are running through these instructions yourself, you'll want to
replace <GOOS>/<GOARCH>
with your particular operating system and compilation architecture.
-
Build Secretless locally
-
Run a Postgres backend named
sample-pg
:pushd test/pg_handler docker build -t sample-pg -f Dockerfile.pg . docker run -d -p 5432:5432 sample-pg popd
-
Check if Postgres is running and query the database:
$ psql -h localhost -p 5432 -U test dbname=postgres -c "select count(*) from test.test;" count -------- 100000 (1 row)
-
Create a sample secretless.yml file in the project root that has:
version: "2" services: pg_tcp: connector: pg listenOn: tcp://0.0.0.0:15432 credentials: host: from: env get: PG_HOST username: test password: from: env get: PG_PASSWORD
-
The type of profiling is explicitly defined in the initial command that runs Secretless. Run Secretless with the profile desired like so:
$ PG_HOST=localhost \ PG_PASSWORD=test \ ./dist/<GOOS>/<GOARCH>/secretless-broker \ -profile=<cpu or memory> \ -f secretless.yml
Note: The location of the binary may vary across different OS
-
Once Secretless is running, the type of profiling defined in the previous step should state that it has been enabled. It should look something like:
2018/11/21 10:17:13 profile: cpu profiling enabled, /var/folders/wy/f9qn852d5_d4s_g06s1kwjcr0000gn/T/profile789228879/cpu.pprof
Note: The hash observed will be different each time a profile is run.
-
Once the Postgres database and Secretless are spun up, query the database through Secretless by running the provided scripts.
Script for CPU profile:
./bin/cpu_profiling
Script for Memory profile:
./bin/memory_profiling
Note: Ensure that these scripts are given the proper permissions to run
-
Observe results in a PDF format by running:
go tool pprof --pdf dist/<GOOS>/<GOARCH>/secretless-broker /var/path/to/cpu.pprof > file.pdf
Secretless supports using Go plugins to extend its functionality. To learn about writing new Secretless plugins and for more information on the types of plugins we currently support, visit the plugin API directory.
Secretless makes use of some third party libraries using Git Submodules. In the build instructions we cover some of the basics of how to clone the repository and populate the submodules. In this section, we cover how to work in the submodules of the Secretless project.
Development on submodules is similar to just working with a second repository, in that
you can cd
into it and check out branches or make separate commits. However, you also
have the ability to commit and push recursively from the parent repository. For help
with this, it is recommended to review the "Publishing Submodule Changes" section of
the Git Submodules documentation.
git submodule update --recursive
can be used to update the registered
submodules to match what the superproject expects by cloning missing submodules and
updating the working tree of the submodules. The "updating" can be done in several
ways depending on command line options and the value of submodule..update
configuration variable. The command line option takes precedence over the
configuration variable. If neither is given, a checkout is performed. The recursive
flag will handle any submodules nested within a submodule
When making a change to a submodule, it will not be committed automatically when the super repository is committed. As such, there are a few steps in place to make sure this happens.
- Enter the submodule directory and create a branch to store your changes, publishing this branch now or once you have completed your work.
cd third_party/<submodule>
git checkout -b <branch name>
-
Commit any neccessary changes within the submodule repository to your new branch. If you haven't pushed the branch, and the changes within, be sure to do so now with
git push
. This is the same workflow, and end result, as if you were working on an individual repository. -
From the super directory, you'll notice that if you run
git status
, it will detect new commits to the repository. For example:
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: third_party/go-mssqldb (new commits)
-
From the super directory, stage the changes to the submodule. It should only require a single
git add <submodule_dir>
statement. This will update the remote that the super repository uses to reference the submodule to point to the new branch you created, and all the commits contained within. -
Push your changes from the super repository. Be sure you are recursively checking for changes to your submodule, so that you don't leave anything behind, with:
git push --recurse-submodules=check
. Again, this check will be performed if you have modified your git config to always recurse into submodules. When you push, the working branch for the super repository will have the commit or branch for the submodule tied to it, but no changes will be made to it beyond what you did yourself in the submodule directory. -
When you create a Pull Review in Github, you will notice that, within the 'files changed' tab, there is a single reference to the changes made in the submodule, with links to the github pages for them as well.
-
Create a seperate Pull Review for your submodule in its respective repository. This is an extra measure to make sure both repositories are reviewed before their changes are merged.
There are a few benefits to this approach
- When a pull request or branch is dependent on a specific commit in a submodule, we can easily pull both at the same time and build without issues.
- Reviewers can see the context for a change that may span more than one repository when Github links the two pull requests.
We want secretless to point to specific commits within a submodule, rather than main. Make sure your change to secretless considers this.
cd
into the submodule- Checkout the commit we want secretless to use from within the submodule
- Return to the secretless-broker directory, and create a new PR with the modified reference
To check the current hash for a submodule:
git ls-tree <branch> third_party/<submodule-directory>
To set (checkout) the SHA-1 of a submodule to the most recent commit:
git submodule --update <optional directory path>
-
Review the changes to
go.mod
since the last release and make any needed updates to NOTICES.txt:- Add any dependencies that have been added since the last tag, including an entry for them alphabetically under the license type (make sure you check the license type for the version of the project we use) and a copy of the copyright later in the same file.
- Update any dependencies whose versions have changed - there are usually at least two version entries that need to be modified, but if the license type of the dependency has also changed, then you will need to remove the old entries and add it as if it were a new dependency.
- Remove any dependencies we no longer include.
If no dependencies have changed, you can move on to the next step.
-
Create a new branch for the version bump.
-
Based on the changelog content, determine the new version number and update.
-
Review the changelog to make sure all relevant changes since the last release have been captured. You may find it helpful to look at the list of commits since the last release - you can find this by visiting the releases page and clicking the "
N commits
to main since this release" link for the latest release.This is also a good time to make sure all entries conform to our changelog guidelines.
-
Commit these changes -
Bump version to x.y.z
is an acceptable commit message - and open a PR for review. Your PR should include updates toCHANGELOG.md
, and if there are any license updates, toNOTICES.txt
.
- Jenkins build parameters can be utilized to release and promote successful builds.
- Merging into main/master branches will automatically trigger a release.
- Reference the internal automated release doc for releasing and promoting.
- Visit the Red Hat project page once the images have been pushed and manually choose to publish the latest release.