Skip to content

Commit 4b65129

Browse files
committed
🔐 Add draft IRP
1 parent b5a1648 commit 4b65129

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+509
-154
lines changed

IRP.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Incident Response Plan (IRP)
2+
3+
Status: Draft
4+
5+
Purpose
6+
-------
7+
This Incident Response Plan (IRP) defines the steps the project maintainer(s) will follow when handling security incidents related to the `oauth2` gem. It is written for a small project with a single primary maintainer and is intended to be practical, concise, and actionable.
8+
9+
Scope
10+
-----
11+
Applies to security incidents that affect the `oauth2` codebase, releases (gems), CI/CD infrastructure related to building and publishing the gem, repository credentials, or any compromise of project infrastructure that could impact users.
12+
13+
Key assumptions
14+
- This project is maintained primarily by a single maintainer.
15+
- Public vulnerability disclosure is handled via Tidelift (see `SECURITY.md`).
16+
- The maintainer will act as incident commander unless otherwise delegated.
17+
18+
Contact & Roles
19+
---------------
20+
- Incident Commander: Primary maintainer (repo owner). Responsible for coordinating triage, remediation, and communications.
21+
- Secondary Contact: (optional) A trusted collaborator or organization contact if available.
22+
23+
If you are an external reporter
24+
- Do not publicly disclose details of an active vulnerability before coordination via Tidelift.
25+
- See `SECURITY.md` for Tidelift disclosure instructions. If the reporter has questions and cannot use Tidelift, they may open a direct encrypted report as described in `SECURITY.md` (if available) or email the maintainer contact listed in the repository.
26+
27+
Incident Handling Workflow (high level)
28+
---------------------------------------
29+
1. Identification & Reporting
30+
- Reports may arrive via Tidelift, issue tracker, direct email, or third-party advisories.
31+
- Immediately acknowledge receipt (within 24-72 hours) via the reporting channel.
32+
33+
2. Triage & Initial Assessment (first 72 hours)
34+
- Confirm the report is not duplicative and gather: reproducer, affected versions, attack surface, exploitability, and CVSS-like severity estimate.
35+
- Verify the issue against the codebase and reproduce locally if possible.
36+
- Determine scope: which versions are affected, whether the issue is in code paths executed in common setups, and whether a workaround exists.
37+
38+
3. Containment & Mitigation
39+
- If a simple mitigation or workaround (configuration change, safe default, or recommended upgrade) exists, document it clearly in the issue/Tidelift advisory.
40+
- If immediate removal of a release is required (rare), consult Tidelift for coordinated takedown and notify package hosts if applicable.
41+
42+
4. Remediation & Patch
43+
- Prepare a fix in a branch with tests and changelog entries. Prefer minimal, well-tested changes.
44+
- Include tests that reproduce the faulty behavior and demonstrate the fix.
45+
- Hardening: add fuzz tests, input validation, or additional checks as appropriate.
46+
47+
5. Release & Disclosure
48+
- Coordinate disclosure through Tidelift per `SECURITY.md` timelines. Aim for a coordinated disclosure and patch release to minimize risk to users.
49+
- Publish a patch release (increment gem version) and an advisory via Tidelift.
50+
- Update `CHANGELOG.md` and repository release notes with non-sensitive details.
51+
52+
6. Post-Incident
53+
- Produce a short postmortem: timeline, root cause, actions taken, and follow-ups.
54+
- Add/adjust tests and CI checks to prevent regressions.
55+
- If credentials or infrastructure were compromised, rotate secrets and audit access.
56+
57+
Severity classification (guidance)
58+
---------------------------------
59+
- High/Critical: Remote code execution, data exfiltration, or any vulnerability that can be exploited without user interaction. Immediate action and prioritized patching.
60+
- Medium: Privilege escalation, sensitive information leaks that require specific conditions. Patch in the next release cycle with advisory.
61+
- Low: Minor information leaks, UI issues, or non-exploitable bugs. Fix normally and include in the next scheduled release.
62+
63+
Preservation of evidence
64+
------------------------
65+
- Preserve all reporter-provided data, logs, and reproducer code in a secure location (local encrypted storage or private branch) for the investigation.
66+
- Do not publish evidence that would enable exploitation before coordinated disclosure.
67+
68+
Communication templates
69+
-----------------------
70+
Acknowledgement (to reporter)
71+
72+
"Thank you for reporting this issue. I've received your report and will triage it within 72 hours. If you can, please provide reproduction steps, affected versions, and any exploit PoC. I will coordinate disclosure through Tidelift per the project's security policy."
73+
74+
Public advisory (after patch is ready)
75+
76+
"A security advisory for oauth2 (versions X.Y.Z) has been published via Tidelift. Please upgrade to version A.B.C which patches [brief description]. See the advisory for details and recommended mitigations."
77+
78+
Runbook: Quick steps for a maintainer to patch and release
79+
---------------------------------------------------------
80+
1. Create a branch: `git checkout -b fix/security-brief-description`
81+
2. Reproduce the issue locally and add a regression spec in `spec/`.
82+
3. Implement the fix and run the test suite: `bundle exec rspec` (or the project's preferred test command).
83+
4. Bump version in `lib/oauth2/version.rb` following semantic versioning.
84+
5. Update `CHANGELOG.md` with an entry describing the fix (avoid exploit details).
85+
6. Commit and push the branch, open a PR, and merge after approvals.
86+
7. Build and push the gem: `gem build oauth2.gemspec && gem push pkg/...` (coordinate with Tidelift before public push if disclosure is coordinated).
87+
8. Publish a release on GitHub and ensure the Tidelift advisory is posted.
88+
89+
Operational notes
90+
-----------------
91+
- Secrets: Use local encrypted storage for any sensitive reporter data. If repository or CI secrets may be compromised, rotate them immediately and update dependent services.
92+
- Access control: Limit who can publish gems and who has admin access to the repo. Keep an up-to-date list of collaborators in a secure place.
93+
94+
Legal & regulatory
95+
------------------
96+
- If the incident involves user data or has legal implications, consult legal counsel or the maintainers' employer as appropriate. The maintainer should document the timeline and all communications.
97+
98+
Retrospective & continuous improvement
99+
-------------------------------------
100+
After an incident, perform a brief post-incident review covering:
101+
- What happened and why
102+
- What was done to contain and remediate
103+
- What tests or process changes will prevent recurrence
104+
- Assign owners and deadlines for follow-up tasks
105+
106+
References
107+
----------
108+
- See `SECURITY.md` for the project's official disclosure channel (Tidelift).
109+
110+
Appendix: Example checklist for an incident
111+
------------------------------------------
112+
- [ ] Acknowledge report to reporter (24-72 hours)
113+
- [ ] Reproduce and classify severity
114+
- [ ] Prepare and test a fix in a branch
115+
- [ ] Coordinate disclosure via Tidelift
116+
- [ ] Publish patch release and advisory
117+
- [ ] Postmortem and follow-up actions

README.md

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,19 +129,19 @@ If it seems like you are in the wrong place, you might try one of these:
129129

130130
## 💡 Info you can shake a stick at
131131

132-
| Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
133-
|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
134-
| Works with JRuby | ![JRuby 9.1 Compat][💎jruby-9.1i] ![JRuby 9.2 Compat][💎jruby-9.2i] ![JRuby 9.3 Compat][💎jruby-9.3i] <br/> [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎10-j-wf] [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
135-
| Works with Truffle Ruby | ![Truffle Ruby 22.3 Compat][💎truby-22.3i] ![Truffle Ruby 23.0 Compat][💎truby-23.0i] <br/> [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
136-
| Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎4-lg-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎6-s-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] |
137-
| Works with MRI Ruby 2 | ![Ruby 2.2 Compat][💎ruby-2.2i] <br/> [![Ruby 2.3 Compat][💎ruby-2.3i]][🚎1-an-wf] [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎1-an-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎1-an-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎7-us-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎7-us-wf] |
138-
| Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
139-
| Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
140-
| Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
141-
| Compliance | [![License: MIT][📄license-img]][📄license-ref] [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
142-
| Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |
143-
| Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |
144-
| `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
132+
| Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
133+
|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
134+
| Works with JRuby | ![JRuby 9.1 Compat][💎jruby-9.1i] ![JRuby 9.2 Compat][💎jruby-9.2i] ![JRuby 9.3 Compat][💎jruby-9.3i] <br/> [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎10-j-wf] [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
135+
| Works with Truffle Ruby | ![Truffle Ruby 22.3 Compat][💎truby-22.3i] ![Truffle Ruby 23.0 Compat][💎truby-23.0i] <br/> [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
136+
| Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎4-lg-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎6-s-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] |
137+
| Works with MRI Ruby 2 | ![Ruby 2.2 Compat][💎ruby-2.2i] <br/> [![Ruby 2.3 Compat][💎ruby-2.3i]][🚎1-an-wf] [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎1-an-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎1-an-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎7-us-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎7-us-wf] |
138+
| Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
139+
| Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
140+
| Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
141+
| Compliance | [![License: MIT][📄license-img]][📄license-ref] [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Incident Response Plan][🔐irp-img]][🔐irp] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
142+
| Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |
143+
| Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |
144+
| `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
145145

146146
### Compatibility
147147

@@ -511,7 +511,7 @@ of a major release, support for that Ruby version may be dropped.
511511
| 3️⃣ | older | N/A | Best of luck to you! | Please upgrade! | |
512512

513513
NOTE: The 1.4 series will only receive critical security updates.
514-
See [SECURITY.md][🔐security].
514+
See [SECURITY.md][🔐security] and [IRP.md][🔐irp].
515515

516516
## ⚙️ Configuration
517517

@@ -1325,7 +1325,7 @@ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed
13251325
To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
13261326
Tidelift will coordinate the fix and disclosure.
13271327

1328-
For more see [SECURITY.md][🔐security].
1328+
For more see [SECURITY.md][🔐security] and [IRP.md][🔐irp].
13291329

13301330
## 🤝 Contributing
13311331

@@ -1648,6 +1648,8 @@ Thanks for RTFM. ☺️
16481648
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.526-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
16491649
[🔐security]: SECURITY.md
16501650
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1651+
[🔐irp]: IRP.md
1652+
[🔐irp-img]: https://img.shields.io/badge/irp-259D6C.svg?style=flat
16511653
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
16521654
[📄license]: LICENSE.txt
16531655
[📄license-ref]: https://opensource.org/licenses/MIT

0 commit comments

Comments
 (0)