We are glad you want to contribute to DevSec! This document will help answer common questions you may have during your first contribution. This project is Apache 2 licensed. Every contribution must be under the Apache 2 License, too. For new files we have added a section with License Headers.
We utilize Github Issues for issue tracking and contributions. You can contribute in two ways:
We have a 3 step process for contributions:
Our projects are built to last. We strive to ensure high quality throughout the experience. In order to ensure this, we require that all pull requests to DevSec projects meet these specifications:
Code review takes place in Github pull requests. See this article if you’re not familiar with Github Pull Requests.
Once you open a pull request, project maintainers will review your code and respond to your pull request with any feedback they might have. The process at this point is as follows:
master
, we may require you to rebase your PR to the latest master
.CHANGELOG.md
.Licensing is very important to open source projects. It helps ensure the software continues to be available under the terms that the author desired.
DevSec uses the Apache 2.0 license to strike a balance between open contribution and allowing you to use the software however you would like to.
The license tells you what rights you have that are provided by the copyright holder. It is important that the contributor fully understands what rights they are licensing and agrees to them. Sometimes the copyright holder isn’t the contributor, such as when the contributor is doing work on behalf of a company.
To make a good faith effort to ensure these criteria are met, DevSec requires the Developer Certificate of Origin (DCO) process to be followed.
The DCO is an attestation attached to every contribution made by every developer. In the commit message of the contribution, the developer simply adds a Signed-off-by statement and thereby agrees to the DCO, which you can find below or at http://developercertificate.org/.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the
best of my knowledge, is covered under an appropriate open
source license and I have the right under that license to
submit that work with modifications, whether created in whole
or in part by me, under the same open source license (unless
I am permitted to submit under a different license), as
Indicated in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including
all personal information I submit with it, including my
sign-off) is maintained indefinitely and may be redistributed
consistent with this project or the open source license(s)
involved.
The DCO requires a sign-off message in the following format appear on each commit in the pull request:
Signed-off-by: Christoph Hartmann <chris@dev-sec.io>
You have to use your real name (sorry, no pseudonyms or anonymous contributions.)
The DCO text can either be manually added to your commit body, or you can add either -s or –signoff to your usual git commit commands. If you forget to add the sign-off you can also amend a previous commit with the sign-off by running git commit –amend -s. If you’ve pushed your changes to Github already you’ll need to force push your branch after this with git push -f.
Below, replace “REPO” with the project that should be changed. Replace “USER” with your GitHub username.
See Mastering Issues for details
Fork the repository on GitHub.
HardeningFramework/REPO -> USER/REPO
You can replace REPO in your fork with a name for the repository that makes it unique, if required.
Clone the repository locally
git clone git@github.com:USER/REPO.git
Ensure the origin is your repository.
git config remote.origin.url git@github.com:USER/REPO.git
Add Hardening Framework REPOs as a remote named upstream
and track it
instead of your origin.
git remote add upstream git://github.com/hardening-io/REPO.git
git config branch.master.remote upstream
Make sure your master branch is updated.
git checkout master
git pull --rebase
Create a new branch for the ticket.
git checkout -b ISSUE-####
Make your changes and push the branch to your origin.
git push origin ISSUE-####
Reference the ISSUE in your Github Pull Request. We will review the issue and contribution as soon as possible.
In order to have your contribution accepted as quickly as possible, we have some requests for you. These make it easier to merge contributions without merge conflicts, and keep the scope on topic for a specific issue.
# encoding: utf-8
#
# Copyright 2018, DevSec Hardening Framework Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
/* Copyright 2018 DevSec Hardening Framework Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
# Copyright 2018 DevSec Hardening Framework Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
<!--
Copyright 2018 DevSec Hardening Framework Team
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
We run several linting tools in our continuous integration pipeline. If you create a pull request the CI will kick in and run Rubocop for every project as well as Foodcritic for chef repos or puppet-lint for puppet repos. The tasks are provided as Rake Tasks ready to run an give feedback.
Here the example output of the chef-os-hardening project (kitchen-tasks stripped):
± bundle exec rake -T
rake acceptance # Alias for kitchen:all
rake foodcritic # Run foodcritic lint checks
rake integration # Run all tests except Kitchen (default task)
rake kitchen:all # Run all test instances
[ ... kitchen-tasks stripped ... ]
rake lint # Run linters
rake rubocop # Run Rubocop lint checks
rake run_all_linters # Run all linters: rubocop and foodcritic
rake spec # Run chefspec tests
rake test # Run all tests
The CI is configured to run the common task rake run_all_linters
in all the projects. Example of a successful run:
± bundle exec rake run_all_linters
Running RuboCop...
Inspecting 20 files
....................
20 files inspected, no offences detected
Running Foodcritic tests...
done.
± echo $?
0
The CI evaluates the return code of the task, which is 0
if no offences are found.
The task will fail fast. Meaning we run Rubocop first and the specific linter (if any) next. A failed run of rubocop looks like the following output:
± bundle exec rake run_all_linters
Running RuboCop...
Inspecting 20 files
....C...............
Offences:
recipes/default.rb:22:1: C: Extra blank line detected.
20 files inspected, 1 offence detected
RuboCop failed!
± echo $?
1
The exit code is 1
indicating that one of the linters involved found an offence. Following an example in a chef cookbook were rubocop is successful but foodcritic found an offence:
± bundle exec rake run_all_linters
Running RuboCop...
Inspecting 20 files
....................
20 files inspected, no offences detected
Running Foodcritic tests...
done.
FC019: Access node attributes in a consistent manner: /.../recipes/default.rb:29
rake aborted!
FC019: Access node attributes in a consistent manner: /.../recipes/default.rb:29
/.../.rvm/gems/ruby-2.1.1/gems/foodcritic-3.0.3/lib/foodcritic/rake_task.rb:33:in `block in define'
/.../.rvm/gems/ruby-2.1.1/bin/ruby_executable_hooks:15:in `eval'
/.../.rvm/gems/ruby-2.1.1/bin/ruby_executable_hooks:15:in `<main>'
Tasks: TOP => run_all_linters => foodcritic
(See full trace by running task with --trace)
± echo $?
1
Rubocop catches a lot of basic syntax infractions and provides ruby best practice advise like using double quotes for strings that do not interpolate Ruby variables, or using simple if/else statements when a one-line ternary operator would be sufficient. This helps enforcing a common style guide and avoiding time consuming best practice discussions in pull requests. Have a look at A community-driven Ruby coding style guide for further details.
Every project has a rake task to run rubocop as well as a task were all linters for the project are run, including rubocop:
± bundle exec rake -T|grep rubocop
rake rubocop # Run Rubocop lint checks
rake run_all_linters # Run all linters: rubocop and foodcritic
Rubocop honors the .rubocop.yml
file of the project.
Example successful run of rubocop:
± bundle exec rake rubocop
Running RuboCop...
Inspecting 6 files
......
6 files inspected, no offences detected
± echo $?
0
Foodcritic is a special linter for chef cookbooks. The rake task is configured to fail on any
violation. We, as a project, decided to use the single quoted string node attribute notation to honor FC019.
There are some edge cases were, upon discussion a violation is tolerated. This can be done with a special markup in the code itself. Following an example (taken from chef-ssh-hardening server.rb)
search('users', "#{field}:*").map do |v| # ~FC003 ignore footcritic violation
Chef::Log.info "ssh_server: installing ssh-keys for root access of user #{v['id']}"
v[field]
end.flatten
Here we acknowledge FC003 as this cookbook will always need search in order to work and we use solo-search in testing.
Every chef project has a rake task to run foodcritic as well as a task were all linters for the project are run, including rubocop:
± bundle exec rake -T |grep foodcritic
rake foodcritic # Run foodcritic lint checks
rake run_all_linters # Run all linters: rubocop and foodcritic
Example successful run of foodcritic
± bundle exec rake foodcritic
Running Foodcritic tests...
done.
± echo $?
0
Puppet-Lint is a special linter for puppet modules. The rake task is configured to fail on any
violation.
± bundle exec rake -T |grep puppet-lint
rake lint # Run puppet-lint / Check puppet manifests with puppet-lint
rake run_all_linters # Run all linters: rubocop and puppet-lint
We disabled some checks from puppet-lint
± grep Lint Rakefile
PuppetLint.configuration.send('disable_autoloader_layout')
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_inherits_across_namespaces')
PuppetLint.configuration.fail_on_warnings = true
PuppetLint.configuration.ignore_paths = ['vendor/**/*.pp']
If everything is well the exit code is 0, and no further output is displayed:
± bundle exec rake lint
± echo $?
0
If there is an error or a warning you get some output and an exit code <> 0
± bundle exec rake lint
manifests/init.pp - WARNING: double quoted string containing no variables on line 10
rake aborted!
/.../.rvm/gems/ruby-2.1.1/gems/puppet-lint-0.3.2/lib/puppet-lint/tasks/puppet-lint.rb:25:in `block (2 levels) in initialize'
/.../.rvm/gems/ruby-2.1.1/gems/puppet-lint-0.3.2/lib/puppet-lint/tasks/puppet-lint.rb:13:in `block in initialize'
/.../.rvm/gems/ruby-2.1.1/bin/ruby_executable_hooks:15:in `eval'
/.../.rvm/gems/ruby-2.1.1/bin/ruby_executable_hooks:15:in `<main>'
Tasks: TOP => lint
(See full trace by running task with --trace)
± echo $?
1
Our release process has following steps:
Example of such announcement mail:
Subject: chef-os-hardening 3.2.1 is released
DevSec Hardening Framework project is releasing a new patch release of chef-os-hardening 3.2.1 today!
Fixed bugs:
• execute[update-pam] resource fails on Ubuntu 14.04 on Azure #237
• exec-shield incompatible with Oracle Linux UEK #234
Merged pull requests:
• Use full path for executing pam-auth-update #238 (sean-nixon)
• Do not apply exec-shield if running Oracle Linux with UEK - addresses #234 #235 (eyespies)
We are looking forward to get your feedback via our new mailing lists (https://dev-sec.io/community/).
Feel free to follow us on Twitter (https://twitter.com/devsecio) to stay updated.