Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .github/.keep
Empty file.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,4 +256,17 @@ Submit via your repository:
```
4. Create a working branch. Implement changes via pull requests with reviews (ask a peer to review).
5. Add security scanning, pre-commit hooks, CI, and docs. Configure branch protection on `main`.
6. Complete the three breakout exercises as practice; then finalize your repository and written components.
6. Complete the three breakout exercises as practice; then finalize your repository and written components.




## Breakout Exercises Answers

- [Code Review Exercise](code_review_exercise.md)
- [Merge Conflict Exercise](merge_conflict_exercise.md)
- [Crisis Management Exercise](crisis_management_exercise.md)

## Notes
- [Code Review Notes](code_reviewNotes.txt)
- [Merge Conflict Notes](merge_conflictNotes.txt)
31 changes: 31 additions & 0 deletions breakout-exercises/code_reviewNotes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
The 6 biggest problems (in plain words)

Passwords are stored as plain text
→ If the database leaks, all user passwords are exposed.
→ Should use bcrypt/argon2 hashing.
→ Priority: Critical

SQL query is built using string formatting
→ Hackers can type trick inputs to break in (SQL injection).
→ Should use parameterized queries.
→ Priority: Critical

Secrets (API key and DB password) are written directly in the file
→ Anyone who sees the repo has the keys.
→ Should load them from environment variables.
→ Priority: Critical

Passwords get printed in the logs
→ Even if the DB is secure, logs could leak private data.
→ Should log only usernames or request IDs, not secrets.
→ Priority: High

There’s a secret backdoor admin check
→ Anyone who uses user_id=1 or "admin" gets full power.
→ Should store user roles in the DB and check them safely.
→ Priority: Critical

External API call has no timeout or error handling
→ If the server doesn’t respond, your app could hang forever.
→ Should use timeout=5 and check responses.
→ Priority: High
76 changes: 70 additions & 6 deletions breakout-exercises/code_review_exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,56 @@ import requests
import sqlite3
import hashlib

# 🔴 SECURITY: Hardcoded secrets (API key & DB creds)
# Don't Hard Code API KEY, please use .env file
API_KEY = "sk-live-1234567890abcdef"
DATABASE_URL = "postgresql://admin:password123@localhost/prod"

# 🟠 SECURITY: DEBUG flag enabled by default
# risks verbose logging and debug behaviors in prod.
DEBUG_MODE = True

def authenticate_user(username, password):
conn = sqlite3.connect("users.db")
# Vulnerable:
# 🔴 SECURITY: Sensitive data logging
query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"

result = conn.execute(query).fetchone()


# High Security Issue printing password
# Queries assume plaintext storage; reset_password writes new password in plaintext.
# Store hashed passwords (argon2/bcrypt) and verify securely:
print(f"Login attempt: {username}:{password}")

# 🟠 SECURITY: Unvalidated/unbounded external API call
# no timeout, error handling, or response validation.
response = requests.post("https://api.auth.com/verify",
data={"user": username, "key": API_KEY})

# 🟠 SECURITY: Returning raw upstream JSON to callers
# leaks third-party schema/errors to clients.
return response.json()

def reset_password(user_id, new_password):
conn = sqlite3.connect("users.db")

# Vulnerable:
# Queries assume plaintext storage; reset_password writes new password in plaintext.
# Store hashed passwords (argon2/bcrypt) and verify securely:
query = f"UPDATE users SET password='{new_password}' WHERE id={user_id}"
conn.execute(query)
conn.commit()


# 🟠 SECURITY/RELIABILITY: DB connection handling & resource leaks
# connections are never closed; no context managers or error handling.

def hash_password(password):
# 🔴 SECURITY: Weak hashing (MD5)
# cryptographically broken and unsalted.
return hashlib.md5(password.encode()).hexdigest()


# 🔴 SECURITY: Insecure admin/backdoor check
# assumes magic values confer admin.
def admin_check(user_id):
if user_id == 1 or user_id == "admin":
return True
Expand Down Expand Up @@ -87,17 +111,54 @@ secure_example()

## Team Discussion (5 minutes)

**Share with your breakout room:**
** Share with your breakout room: **
1. Which issues did you find?
- Hardcoded secrets (API key, DB credentials)
- SQL injection in string-formatted queries
- Plaintext password storage & use of MD5
- Logging sensitive data (username + password)
- Insecure admin_check backdoor
- Debug mode enabled in production
- Unvalidated/unbounded external API call

2. Which ones did you miss?
I had to have chat help me with all of this pretty much. I found 2 or 3 myself and the rest came from ai.

3. How would you prioritize fixing them?
Critical fixes first: Remove hardcoded secrets, replace plaintext/MD5 with Argon2/Bcrypt, and parameterize SQL queries.
- High priority: Remove sensitive logging, secure the admin check, and fix the external API call (timeouts, headers, validation).
- Medium priority: Disable debug in production, close DB connections properly, validate inputs, and prevent brute force attacks.
- Low priority: Standardize return values instead of exposing raw JSON.


4. What was challenging about writing professional review comments?
- Balancing technical accuracy with clarity so comments are understandable.
- Avoiding being too harsh—framing feedback as constructive.
- Providing not just what’s wrong, but why it matters and how to fix it.
- Deciding which issues are most important to highlight given limited time.


**Discussion Questions:**
- What makes a code review comment helpful vs. just critical?

Helpful comments explain the impact of the issue and suggest a fix.
Critical-only comments just say “this is wrong” without context.


- How do you balance being thorough with being constructive?

Focus on the biggest risks first, then note smaller improvements if time allows.
Phrase comments in a supportive way: “Consider changing X for better security” instead of “This is bad.”


- What would you want to see in a review of your own code?

- Clear, specific explanations of problems.
- Example code showing a safer or cleaner approach.
- Prioritization (what must be fixed now vs. what can wait).
- Respectful tone that assumes good intent.


---

---
Expand All @@ -110,4 +171,7 @@ These are the exact types of issues you'll encounter in professional code review
- **Weak password hashing** affects millions of users
- **Missing input validation** leads to data breaches

The review skills you practice here directly apply to protecting your team's production systems.
The review skills you practice here directly apply to protecting your team's production systems.



61 changes: 56 additions & 5 deletions breakout-exercises/crisis_management_exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
Choose the correct first step:
- [ ] A) Remove the secrets from the current code
- [ ] B) Make the repository private
- [ ] C) Rotate/revoke the compromised credentials immediately
- [x] C) Rotate/revoke the compromised credentials immediately
- [ ] D) Delete the problematic commits

**Why is this the right first step?**
_________________________________
- Why: Even if you delete the keys from Git, they’re already out there — anyone could’ve copied them in the last 2 hours. So the very first thing is to disable those old keys and create new ones.

### Phase 2: Git History Cleanup (Next 4 minutes)

Expand All @@ -36,7 +36,7 @@ _________________________________
git log --oneline -5
a1b2c3d Fix user authentication bug
e4f5g6h Update README documentation
i7j8k9l Add production configuration ← API keys are in this commit!
i7j8k9l Add production configuration ← API keys are in this commit! <--BAD COMMIT(KEYS INSIDE)
m1n2o3p Add user management features
q4r5s6t Initial project setup
```
Expand All @@ -56,7 +56,7 @@ git rebase -i HEAD~3
```

**Which option would you choose and why?**
_________________________________
👉 For most class/team projects, the safe answer is: use git revert. That way, you don’t rewrite history and confuse everyone. It just makes a new commit that “undoes” the secrets.

### Phase 3: Prevention Implementation (Last 3 minutes)

Expand All @@ -83,7 +83,36 @@ fi

3. **Document the incident:**
What would you write in your incident report?
_________________________________
chatgpt:
## Incident Report – Exposed Credentials

**What happened (Summary):**
API keys were accidentally committed to main in commit `i7j8k9l` and pushed to a public repo.

**Timeline:**
- T0: Commit with keys pushed to GitHub (public)
- T+2h: Exposure discovered
- T+2h + 5m: Keys rotated/revoked
- T+2h + 15m: Git history cleaned (revert)
- T+2h + 30m: Prevention measures added (.gitignore, pre-commit hook, docs)

**Impact:**
Potential unauthorized access with exposed keys while active. No confirmed misuse yet.

**Immediate Actions Taken:**
- Rotated/revoked exposed credentials immediately.
- Removed secrets from code and created a clean commit (revert).
- Searched history for other secrets.
- Opened ticket to monitor logs for suspicious activity.

**Root Cause:**
Secrets were stored in code instead of environment variables. No pre-commit scanning in place.

**Prevention / Follow-ups:**
- Use environment variables and a `.env` file (ignored by git).
- Add pre-commit secret scanning.
- Team reminder/training on secret handling.
- Consider enabling repo secret scanning in CI.

---

Expand All @@ -93,13 +122,35 @@ _________________________________

### Crisis Response Questions:
1. **Speed vs. Safety:** When would you choose history rewrite vs. revert?
Revert if anyone else might have pulled the bad commit (safer, no history rewrite).
Rewrite (rebase -i) only if it’s certain nobody else has it yet (solo work).

2. **Communication:** Who would you notify during this incident?
Teammates/instructor, whoever manages the credentials (DevOps/security), and anyone relying on the keys (downstream services).

3. **Prevention:** What other security measures could prevent this?
Environment variables + .env (gitignored).
Secret scanning (pre-commit, CI, or GitHub’s built-ins).
Least-privilege keys and key rotation policy.
Code reviews with a “no secrets in code” checklist.




### Git Command Practice:
1. **Have you used `git revert` vs `git rebase -i` before?**
NOPE
2. **What's the difference between `git reset` and `git revert`?**
revert makes a new commit that undoes another (safe on shared branches).
rebase -i edits history (only safe if nobody else has pulled).
reset moves your branch pointer (can drop commits from history).
revert adds a new commit to undo changes (history stays intact).

3. **When is `git push --force` acceptable?**
On your own branch or when the team explicitly agrees.
Prefer --force-with-lease to avoid overwriting others’ work.



### Real-World Experience:
1. **Has anyone experienced a similar incident?**
Expand Down
73 changes: 73 additions & 0 deletions breakout-exercises/merge_conflictNotes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
The Story in Normal Words

Imagine two friends are both working on the same recipe at the same time.

Friend A is focused on making the food safe and healthy — they wash the veggies, make sure nothing is raw, and wrap things up cleanly.

Friend B is focused on making the food last longer — they buy containers, put labels on them, and store everything in the fridge.

Now you’ve got two versions of the recipe. The problem: you need one final recipe that has both safety AND storage built in.

That’s basically what’s happening with Branch A and Branch B.

What Branch A Did (Authentication)

Checks if the username and password are “good enough.”

Turns the password into a scrambled code (so no one sees the real one).

Lets people log in and get a “ticket” (JWT token) so they can prove who they are.

👉 Think: locks on the door + ID badges.

What Branch B Did (Database)

Builds a place (database) to actually store users.

Creates a system to add new users and list them later.

👉 Think: a filing cabinet with folders for each person.

The Conflict

Both friends wrote a “recipe step” for creating a user — but one focuses on security checks, and the other focuses on saving to the filing cabinet. If you just pick one, you lose the other.

The Smart Merge Plan

Use Branch B’s filing cabinet (database) so users are saved.

Add Branch A’s locks and ID badges (password hashing, tokens).

Make sure you check IDs before you file them (validation).

Don’t keep any sensitive stuff visible (no storing plain passwords).

What You’d Double-Check After Combining

Can you add a new user safely (rules + goes into the cabinet)?

Is the password scrambled, not written down in plain text?

Can people log in and get their “badge” (JWT)?

Can you still see a list of users, but without their secret info?

What happens if someone tries to use a short name, weak password, or sign up twice?

Why This Matters

If you do the merge “the smart way,” you get the best of both friends:

Safe and secure (thanks, Friend A).

Organized and stored (thanks, Friend B).

If you just “pick one side,” you either end up with:

A safe system that forgets everything, OR

A storage system that’s unsafe.

Neither is good.

👉 That’s all this exercise really means: take the best pieces of two different solutions, put them together carefully, and make sure you test that the final version actually works.
Loading