Skip to content
Merged
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
40 changes: 40 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
version: 2
updates:
# Python dependencies via Poetry
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
groups:
python-minor:
patterns:
- "*"
update-types:
- "minor"
- "patch"
labels:
- "dependencies"
- "python"

# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "github-actions"

# Docker
- package-ecosystem: "docker"
directory: "/docker"
schedule:
interval: "weekly"
day: "monday"
labels:
- "dependencies"
- "docker"
189 changes: 189 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
name: CI

on:
push:
branches: [master]
pull_request:
branches: [master]

env:
POETRY_VERSION: "2.3.0"
POETRY_VIRTUALENVS_IN_PROJECT: true

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.14"

- name: Load cached Poetry installation
id: cached-poetry
uses: actions/cache@v4
with:
path: ~/.local
key: poetry-${{ env.POETRY_VERSION }}-${{ runner.os }}

- name: Install Poetry
if: steps.cached-poetry.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1
with:
version: ${{ env.POETRY_VERSION }}
virtualenvs-create: true
virtualenvs-in-project: true

- name: Load cached venv
id: cached-venv
uses: actions/cache@v4
with:
path: .venv
key: venv-lint-${{ runner.os }}-py3.14-${{ hashFiles('poetry.lock') }}
restore-keys: |
venv-lint-${{ runner.os }}-py3.14-

- name: Install dependencies
if: steps.cached-venv.outputs.cache-hit != 'true'
run: poetry install --only dev --no-interaction

- name: Run Ruff linter
run: poetry run ruff check .

- name: Run Ruff formatter check
run: poetry run ruff format --check .

test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python 3.14
uses: actions/setup-python@v5
with:
python-version: "3.14"

- name: Load cached Poetry installation
id: cached-poetry
uses: actions/cache@v4
with:
path: ~/.local
key: poetry-${{ env.POETRY_VERSION }}-${{ runner.os }}

- name: Install Poetry
if: steps.cached-poetry.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1
with:
version: ${{ env.POETRY_VERSION }}
virtualenvs-create: true
virtualenvs-in-project: true

- name: Load cached venv
id: cached-venv
uses: actions/cache@v4
with:
path: .venv
key: venv-test-${{ runner.os }}-py3.14-${{ hashFiles('poetry.lock') }}
restore-keys: |
venv-test-${{ runner.os }}-py3.14-

- name: Install dependencies
if: steps.cached-venv.outputs.cache-hit != 'true'
run: poetry install --no-interaction

- name: Run tests with coverage
run: |
poetry run pytest \
--cov=pybot \
--cov-report=xml \
--cov-report=term-missing \
-v \
--tb=short
env:
SLACK_TOKEN: "xoxb-test-token"
SLACK_ADMIN_TOKEN: "xoxb-admin-test-token"
AIRTABLE_API_KEY: "test-key"
AIRTABLE_BASE_ID: "test-base"

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
files: ./coverage.xml
fail_ci_if_error: false
verbose: true

security:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python 3.14
uses: actions/setup-python@v5
with:
python-version: "3.14"

- name: Load cached Poetry installation
id: cached-poetry
uses: actions/cache@v4
with:
path: ~/.local
key: poetry-${{ env.POETRY_VERSION }}-${{ runner.os }}

- name: Install Poetry
if: steps.cached-poetry.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1
with:
version: ${{ env.POETRY_VERSION }}
virtualenvs-create: true
virtualenvs-in-project: true

- name: Load cached venv
id: cached-venv
uses: actions/cache@v4
with:
path: .venv
key: venv-security-${{ runner.os }}-py3.14-${{ hashFiles('poetry.lock') }}
restore-keys: |
venv-security-${{ runner.os }}-py3.14-

- name: Install dependencies
if: steps.cached-venv.outputs.cache-hit != 'true'
run: poetry install --no-interaction

- name: Run Bandit security linter
run: poetry run bandit -r pybot -x pybot/_vendor --skip B101 -f json -o bandit-report.json || true

- name: Display Bandit results
run: poetry run bandit -r pybot -x pybot/_vendor --skip B101 -f txt || true

- name: Check for known vulnerabilities
run: poetry run safety scan --output text || true
continue-on-error: true

# Final status check for branch protection
ci-success:
name: CI Success
needs: [lint, test, security]
runs-on: ubuntu-latest
if: always()
steps:
- name: Check all jobs passed
run: |
if [[ "${{ needs.lint.result }}" != "success" ]]; then
echo "Lint job failed"
exit 1
fi
if [[ "${{ needs.test.result }}" != "success" ]]; then
echo "Test job failed"
exit 1
fi
# Security is informational, doesn't fail CI
echo "All required jobs passed!"
31 changes: 12 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
<div align="center">
<a href="https://operationcode.org" height="750" width="750">
<a href="https://operationcode.org">
<img
alt="Operation Code Hacktoberfest Banner"
src="https://operation-code-assets.s3.us-east-2.amazonaws.com/operationcode_hacktoberfest_2020.jpg"
alt="Operation Code Logo"
src="https://operation-code-assets.s3.us-east-2.amazonaws.com/branding/logos/large-blue-logo.png"
width="400"
>
</a>
</div>
<br />
<br />


<br />

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Twitter Follow](https://img.shields.io/twitter/follow/operation_code.svg?style=social&label=Follow&style=social)](https://twitter.com/operation_code)
[![Code-style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)


[![CircleCI](https://circleci.com/gh/OperationCode/operationcode-pybot.svg?style=svg)](https://circleci.com/gh/OperationCode/operationcode-pybot)
[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=OperationCode/operationcode-pybot)](https://dependabot.com)
[![CI](https://github.com/OperationCode/operationcode-pybot/actions/workflows/ci.yml/badge.svg)](https://github.com/OperationCode/operationcode-pybot/actions/workflows/ci.yml)
[![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://contributor-covenant.org/)

# [OperationCode-Pybot](https://github.com/OperationCode/operationcode-pybot)
Expand All @@ -41,7 +34,7 @@ The vendored code has been modernized with:
- Removed deprecated `asyncio.coroutine()` usage
- Fixed deprecated `loop=` parameter patterns
- Replaced removed `cgi` module with `email.message`
- Added Python 3.12 type hints
- Added Python 3.12+ type hints

## Resources
* [Slack Bot Tutorial](https://www.digitalocean.com/community/tutorials/how-to-build-a-slackbot-in-python-on-ubuntu-20-04)
Expand All @@ -54,9 +47,9 @@ Bug reports and pull requests are welcome on [Github](https://github.com/Operati

## Quick Start
Recommended versions of tools used within the repo:
- `python@3.12` or greater (Python 3.13+ also supported)
- `python@3.14` or greater
- `git@2.17.1` or greater
- `poetry@1.0` or greater
- `poetry@2.0` or greater
- [Poetry](https://python-poetry.org/) is a packaging and dependency manager, similar to pip or pipenv
- Install via: `curl -sSL https://install.python-poetry.org | python3 -`
- See https://python-poetry.org/docs/
Expand All @@ -73,7 +66,7 @@ poetry run python -m pybot
poetry run pytest

# Run formatting and linting
poetry run black pybot/ tests/
poetry run ruff format pybot/ tests/
poetry run ruff check pybot/ tests/
```

Expand Down Expand Up @@ -253,7 +246,7 @@ Command | Description | Usage Hint
/ticket | submit ticket to admins | (text of ticket)


**👋 IMPORTANT!**
**IMPORTANT!**

The `/lunch` command requires a valid Yelp API token stored in the `YELP_TOKEN`
environment variable. See https://www.yelp.com/developers/faq
Expand All @@ -264,7 +257,7 @@ functionality please reach out to the `#oc-python-projects` channel for help get

### Airtable Authentication

**⚠️ IMPORTANT:** Airtable deprecated API keys on February 1, 2024. You must use a **Personal Access Token (PAT)**:
**IMPORTANT:** Airtable deprecated API keys on February 1, 2024. You must use a **Personal Access Token (PAT)**:

1. Go to [Airtable Developer Hub](https://airtable.com/create/tokens)
2. Click **Create new token**
Expand Down
4 changes: 3 additions & 1 deletion manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ async def replay_team_join(
except Exception as e:
logger.error(f" Failed to link backend user: {e}")
else:
logger.error(" Backend authentication failed - check BACKEND_USERNAME/BACKEND_PASS")
logger.error(
" Backend authentication failed - check BACKEND_USERNAME/BACKEND_PASS"
)
else:
logger.info("Skipping backend linking (--skip-backend)")

Expand Down
Loading