Contribute to Ory
Introduction
You can contribute in many ways beyond writing code. The goal of this document is to provide a high-level overview of how you can get involved.
Please note: We are serious about Ory's security and our users' trust. If you believe you have found a security issue in Ory, please disclose by contacting us at security@ory.sh.
First: As a potential contributor, your changes and ideas are welcome at any hour of the day or night, weekdays, weekends, and holidays. Please do not ever hesitate to ask a question or send a pull request.
If you are unsure, just ask or submit the issue or pull request anyways. You won't be yelled at for giving it your best effort. The worst that can happen is that you'll be asked to change something. We appreciate any sort of contributions, and don't want a wall of rules to get in the way of that.
That said, if you want to ensure that a pull request is going to be merged, talk to us! You can find out our thoughts and ensure that your contribution won't clash with Ory's normal direction. A great way to do this is via GitHub Discussions ((Ory Cloud, Ory Kratos, Ory Hydra, Ory Keto, Ory Oathkeeper)) or the Ory Chat.
Frequently asked questions
I am new to the community. Where can I find the Ory Community Code of Conduct?
I have a question. Where can I get answers to questions?
I would like to contribute but I am not sure how. Are there easy ways to contribute? Or good first issues?
I want to talk to other Ory users. How can I become a part of the community?
I would like to know what I am agreeing to when I contribute to Ory. Does Ory have a Contributors License Agreement?
I would like updates about new versions of Ory. How are new releases announced?
How can I contribute?
If you want to start contributing code right away, we have a list of good first issues.
You can contribute without writing any code in multiple ways . Here are a few things you can do to help out:
Give us a star. It may not seem like much, but it really makes a difference. This is something that everyone can do to help out Ory. Github stars help the project gain visibility and stand out.
Join the community. Sometimes helping people can be as easy as listening to their problems and offering a different perspective. Join our Slack, have a look at discussions on GitHub and take part in events like the Community Calls. More info on this in Communication.
Helping with open issues. We have a lot of open issues for Ory and some of them may lack necessary information, some are duplicates of older issues. You can help out by guiding people through the process of filling out the issue template, asking for clarifying information, or pointing them to existing issues that match their description of the problem.
Reviewing documentation changes. Most documentation just needs a review for proper spelling and grammar. If you think you can improve a document in any way, feel free to hit the
edit
button at the top of the page. More info on contributing to documentation here.Help with tests. Some pull requests may lack proper tests or test plans. These are needed for the change to be implemented.
Communication
We use Slack. You are welcome to drop in and ask questions, discuss bugs and feature requests, talk to other users of Ory, etc.
Check out [Discussions] for Ory Cloud, Ory Kratos, Ory Hydra, Ory Keto, Ory Oathkeeper, and more. This is a great place for in-depth discussions and lots of code examples, logs and similar data.
You can also join our community hangout, if you want to speak to the Ory team directly or ask some questions. You can find more info on the hangouts in Slack.
If you want to receive regular notifications about updates to Ory, consider joining the mailing list. We will only send you vital information on the projects that you are interested in.
Also follow us on twitter.
Conduct
Whether you are a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
- We are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, disability, ethnicity, religion, or similar personal characteristic.
- Please avoid using nicknames that might detract from a friendly, safe and welcoming environment for all.
- Be kind and courteous. Don't be mean or rude.
- We will exclude you from interaction if you insult, demean or harass anyone. In particular, we do not tolerate behavior that excludes people in socially marginalized groups.
- Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact a member of the Ory team.
- Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
We welcome discussion about creating a welcoming, safe, and productive environment for the community. If you have any questions, feedback, or concerns please let us know.
Contributing Code
Unless you are fixing a known bug, we strongly recommend discussing it with the core team via a GitHub issue or in our chat before getting started to ensure your work is consistent with Ory's road map and architecture.
All contributions are made via pull requests. To make a pull request, you will need a GitHub account; if you are unclear on this
process, see GitHub's documentation on forking and
pull requests. Pull requests should be targeted at the master
branch.
Before creating a pull request, go through this checklist:
- Create a feature branch off of
master
so that changes do not get mixed up. - Rebase your local changes against the
master
branch. - Run the full project test suite with the
go test -tags sqlite ./...
(or equivalent) command and confirm that it passes. - Run
make format
if aMakefile
is available,gofmt -s
if the project is written in Go,npm run format
if the project is written for NodeJS. - Ensure that each commit has a descriptive prefix. This ensures a uniform commit history and helps structure the changelog.
Please refer to this list of prefixes for Kratos for an overview. - Sign-up with CircleCI so that it has access to your repository with the branch containing your PR. Simply creating a CircleCI account is sufficient for the CI jobs to run, you do not need to setup a CircleCI project for the branch.
If a pull request is not ready to be reviewed yet it should be marked as a "Draft".
Before your contributions can be reviewed you need to sign our Contributor License Agreement.
This agreement defines the terms under which your code is contributed to Ory. More specifically it declares that you have the right to, and actually do, grant us the rights to use your contribution. You can see the Apache 2.0 license under which our projects are published here.
When pull requests fail testing, authors are expected to update their pull requests to address the failures until the tests pass.
Pull requests eligible for review
- follow the repository's code formatting conventions;
- include tests which prove that the change works as intended and does not add regressions;
- document the changes in the code and/or the project's documentation;
- pass the CI pipeline;
- have signed our Contributor License Agreement;
- include a proper git commit message following the Conventional Commit Specification.
If all of these items are checked, the pull request is ready to be reviewed and you should change the status to "Ready for review" and request review from a maintainer.
Reviewers will approve the pull request once they are satisfied with the patch.
Documentation
Please provide documentation when changing, removing, or adding features. Documentation resides in the Ory docs repository folder.
For further instructions please head over to docs/README.md.
Disclosing vulnerabilities
Please disclose vulnerabilities to security@ory.sh. Do not use GitHub issues.
Code Style
Please follow these guidelines when formatting source code:
- Go code should match the output of
gofmt -s
and passgolangci-lint run
. - Format NodeJS and JavaScript code using
npm run format
where appropriate.
Working with Forks
# First you clone the original repository
git clone git@github.com:ory/ory/kratos.git
# Next you add a git remote that is your fork:
git remote add fork git@github.com:<YOUR-GITHUB-USERNAME-HERE>/ory/kratos.git
# Next you fetch the latest changes from origin for master:
git fetch origin
git checkout master
git pull --rebase
# Next you create a new feature branch off of master:
git checkout my-feature-branch
# Now you do your work and commit your changes:
git add -A
git commit -a -m "fix: this is the subject line" -m "This is the body line. Closes #123"
# And the last step is pushing this to your fork
git push -u fork my-feature-branch
Now go to the project's GitHub Pull Request page and click "New pull request"
This document is a work in progress and documents the inner workings of the Ory GitHub ecosystem and project structures, as well as providing more in-depth tips & guides to contributors. If you feel there is something missing or should be added, please open an issue in ory/docs or contact us in the Ory Chat. We also offer discussions on GitHub for all major projects: Ory Kratos, Ory Hydra, Ory Keto, Ory Oathkeeper, as well as one for all other Ory projects, events and content: Ory Meta discussions.
Releasing Software
To release a project, run the following bash command in the root of the project you would like to release. The first argument can be one of:
patch
bumpsv1.2.3
tov1.2.4
(doesn't work for pre-releases such asv1.2.3-beta.1
)minor
bumpsv1.2.3
tov1.3.0
(doesn't work for pre-releases such asv1.2.3-beta.1
)major
bumpsv1.2.3
tov2.0.0
(doesn't work for pre-releases such asv1.2.3-beta.1
)- Any semver-valid version, for example
v1.2.3-beta.1
release_as=v1.2.3
bash <(curl -s https://raw.githubusercontent.com/ory/meta/master/scripts/release.sh) $release_as
Defining Release Config
For the scripts to work, the project must be located in a directory structure that reflects the GitHub organization and repository
name, for example: path/to/ory/hydra
.
Goreleaser
We use goreleaser.
The listed configuration options should be included in every .goreleaser.yml
config. Make sure you set env vars and
go mod download
and run e.g. packr2 and other tools first:
env:
- GO111MODULE=on
before:
hooks:
- go mod download
# - go install github.com/gobuffalo/packr/v2/packr2
# - packr2
Tag -alpha.1
and other pre-release tags as pre-release on GitHub:
release:
prerelease: auto
Name snapshot releases -next
:
snapshot:
name_template: "{{ .Tag }}-_next"
If you create a new goreleaser config, you may also want to create the following empty GitHub repositories:
Build and publish on Docker. You need to create a repository on Docker Hub first!
# Build dockerfiles
dockers:
- dockerfile: Dockerfile
binaries:
- $PROJECT_NAME
image_templates:
- "oryd/$PROJECT_NAME:v{{ .Major }}"
- "oryd/$PROJECT_NAME:v{{ .Major }}.{{ .Minor }}"
- "oryd/$PROJECT_NAME:v{{ .Major }}.{{ .Minor }}.{{ .Patch }}"
- "oryd/$PROJECT_NAME:latest"
If you add Scoop (Homebrew for Windows) you must also create a GitHub repository under the ory
org named
scoop-$PROJECT_NAME
(e.g. scoop-hydra
).
scoop:
bucket:
owner: ory
name: scoop-$PROJECT_NAME
homepage: https://www.ory.sh
commit_author:
name: aeneasr
email: aeneas@ory.sh
If you add Homebrew you must also create a GitHub repository under the ory
org named homebrew-$PROJECT_NAME
(e.g. homebrew-hydra
).
brews:
- github:
owner: ory
name: homebrew-$PROJECT_NAME
ids:
- <<REPLACE-WITH-ARCHIVE-ID>>
homepage: https://www.ory.sh
commit_author:
name: aeneasr
email: aeneas@ory.sh
We use the following replacements:
archives:
- replacements:
darwin: macOS
386: 32-bit
amd64: 64-bit
format_overrides:
- goos: windows
format: zip
Update install script
When you have finalized changes to the .goreleaser.yml
, run:
GO111MODULES=off go get -u github.com/goreleaser/godownloader
godownloader .goreleaser.yml --repo=$(basename $(dirname $(pwd)))/$(basename $(pwd)) > ./install.sh
CI
ory/nancy
Enables nancy vulnerability scanning for the repository.
orbs:
nancy: ory/nancy@0.0.9
workflows:
test:
jobs:
- nancy/test:
filters:
tags:
only: /.*/
Toolchain
Checking for vulnerabilities
NodeJS
This is done automatically by GitHub
Go
# Outside of a go module-enabled project:
go get -u github.com/sonatype-nexus-community/nancy
# Inside your go module-enabled project:
go mod list -m all | nancy
Pinning indirect go module dependencies
Sometimes a project has an indirect dependency (another dependency requires that dependency) which doesn't pass, for example,
nancy
vulnerability scanning. Because it's not possible to pin this dependency to a specific version, we need to explicitly
require it. But because it's not directly required by our code, it will be pruned when using go mod tidy
. To prevent that,
create a file which imports the dependency without use:
// +build go_mod_indirect_pins
package main
import _ "github.com/my/dependency"
You would do the same if the project uses dev tools such as packr2
, goimports
, goreturns
, swagutil
, ... as part of e.g.
the Makefile or other scripts.
Development
DBAL gobuffalo/pop
Table Names
Please define custom table names for all table structs. Keep in mind that TableName()
must be a value receiver, not a pointer
receiver, for slices []Model
to work properly:
-func (m *Model) TableName(ctx context.Context) string {
+func (m Model) TableName(ctx context.Context) string {
return "foo"
}
SQL Migrations
Ory uses a lightweight DBAL across all projects that require a database. This DBAL is typically stored in the persistence/
directory. Since we just support SQL at the moment - there are no plans to add new databases and contributions won't be accepted
due to maintenance effort - you will find the implementation in persistence/sql
.
info
This section just applies to Ory Kratos and Ory Keto. Ory Hydra is using an approach that doesn't rely on fizz migrations. Please discuss with maintainers before making changes to the Ory Hydra SQL schemata.
In order to provide a process to upgrade SQL schemata, we use migrations. These migrations are generated using the fizz language and then rendered to SQL using the Ory CLI.
This is necessary because there are differences between the SQL "dialects" of SQLite (doesn't support certain ALTER TABLE
statements for example), PostgreSQL, MySQL, and CockroachDB.
To change the schema, create a new fizz template using:
# In the project root - e.g. /kratos
make .bin/ory
# If make .bin/ory fails use:
# make .bin/cli
#
# and replace `.bin/ory` with `.bin/cli`.
# We're working on streamlining this
# across all repos.
.bin/ory dev pop migration create persistence/sql/migrations/templates descriptive_change
This will create two new files:
ls -la persistence/sql/migrations/templates | tail -n 2
-rw-r--r-- 1 foobar staff 0 Apr 28 17:25 20210428172500_descriptive_change.down.fizz
-rw-r--r-- 1 foobar staff 0 Apr 28 17:25 20210428172500_descriptive_change.up.fizz
Add you fizz migrations there. The up
file is for applying your schema changes, the down
file for reverting them.
Once your migrations are added, it's time to render them to SQL. Make sure that Docker is running and execute:
.bin/ory dev pop migration render persistence/sql/migrations/templates persistence/sql/migrations/sql
If you encounter errors you can also try running this with the --replace
option but please let maintainers know that you used
--replace
in your PR:
.bin/ory dev pop migration render --replace persistence/sql/migrations/templates persistence/sql/migrations/sql
This will render your migrations to SQL files. Add them to git (git add -A
) and commit them.
Next, you need to update the migration tests. To do so, run the sync command:
.bin/ory dev pop migration sync persistence/sql/migrations/templates persistence/sql/migratest/testdata
This will add create a new SQL file:
ls -la persistence/sql/migratest/testdata | tail -n 1
-rw-r--r-- 1 foobar staff 0 Apr 28 17:28 20210428172500_testdata.sql
Add an INSERT
or UPDATE
or DELETE
statement that reflects the changes you have made to the schema to the file. Let's say you
added a new column new_column
to table bar
. In that case, write an INSERT
statement that reflects this:
INSERT INTO bar (old_column, new_column) VALUES ('foo', 'bar');
Next, execute the tests:
cd persistence/sql/migratest
go test -tags sqlite ./...
The tests will probably fail because the fixtures need to be updated. To update them, run:
cd persistence/sql/migratest
go test -tags sqlite,refresh -short .
You might need to run the go test
command two or three times before all fixtures have been updated.
That's it! :)
OpenAPI Spec and Go Swagger
We use go-swagger to generate OpenAPI Spec from source code. Here you can find conventions we use across the code base.
Models
Models should have a descriptive title, a body, and be camelCase. It's good practice to scope the model where needed.
package some
// Title
//
// A description with a trailing dot.
//
// swagger:model someSpecificModel
type SpecificModel struct {}
Routes
Routes should use tags for versioning. If a route is accessible through a privileged port (e.g. admin) it should be prefixed with
admin
.
// swagger:route POST /identities v0alpha1 adminCreateIdentity
Public endpoints don't need a prefix.
// swagger:route POST /something-public v0alpha1 somethingPublic
Parameters
Parameters for routes should have the same name as the route. If they have a body, you must not use an embedded struct and the
struct's model name should be suffixed Body
:
// swagger:parameters adminCreateIdentity
// nolint:deadcode,unused
type adminCreateIdentity struct {
// in: body
Body adminCreateIdentityBody
}
// swagger:model adminCreateIdentityBody
type adminCreateIdentityBody struct {
// SchemaID is the ID of the JSON Schema to be used for validating the identity's traits.
//
// required: true
SchemaID string `json:"schema_id"`
// Traits represent an identity's traits. The identity is able to create, modify, and delete traits
// in a self-service manner. The input will always be validated against the JSON Schema defined
// in `schema_url`.
//
// required: true
Traits json.RawMessage `json:"traits"`
}
// swagger:route POST /identities v0alpha1 adminCreateIdentity
Responses
Where possible use models for responses.
// A list of identities.
// swagger:model identityList
// nolint:deadcode,unused
type identityList []Identity
// swagger:route GET /identities v0alpha0 adminListIdentities
//
// List Identities
//
// Lists all identities. Doesn't support search at the moment.
//
// Learn how identities work in [Ory Kratos' User And Identity Schema Documentation](https://www.ory.sh/docs/next/kratos/concepts/identity-user-model).
//
// Produces:
// - application/json
//
// Schemes: http, https
//
// Responses:
// 200: identityList
// 500: jsonError
IDE Tips
Goland
Goland Tests
While running tests inside the IDE make sure you have the tag -tags sqlite
in the "Go Tool Arguments". In the example screenshot
we're looking at login_test.go
and add it to the Run/Debug Configurations.
Jetbrains
Debugging Tests
Jetbrains IDEs have an SQL debugger, that can open sqlite files. When debugging tests, you can set a bool flag to use an sqlite file instead of in-mem and then debug after the test failed. Example:
func GetSqlite(t testing.TB, mode sqliteMode) *DsnT {
dsn := &DsnT{
MigrateUp: true,
MigrateDown: false,
}
switch mode {
case SQLiteMemory:
dsn.Name = "memory"
dsn.Conn = fmt.Sprintf("sqlite://file:%s?_fk=true&cache=shared&mode=memory", t.Name())
case SQLiteFile:
t.Cleanup(func() {
_ = os.Remove("TestDB.sqlite")
})
fallthrough
case SQLiteDebug:
dsn.Name = "sqlite"
dsn.Conn = "sqlite://file:TestDB.sqlite?_fk=true"
}
return dsn
}
To transfer the above to Kratos:
- Change the DSN to the following:
dsn.Conn = "sqlite://file:TestDB.sqlite?_fk=true"
. mode=memory
.- In case you have an sqlite file, migrators aren't automatically applied. Run them manually first with the CLI.
VS Code
VS Code Tests
- Under Settings, search for
Go: Test Tags
. - Click Edit in
settings.json
. - Add the following KV to the
settings.json
:"go.testTags": "sqlite",
.