diff --git a/.coverage b/.coverage index c94310c..1114189 100644 Binary files a/.coverage and b/.coverage differ diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 80cad71..749cb12 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -2,7 +2,7 @@ name: Dependency Security Audit on: push: - branches: [ "master" ] + branches: [ "dev" ] jobs: security-scan: diff --git a/.github/workflows/auto_merge.yml b/.github/workflows/auto_merge.yml new file mode 100644 index 0000000..7b8e389 --- /dev/null +++ b/.github/workflows/auto_merge.yml @@ -0,0 +1,17 @@ +name: Auto Merge PR + +on: + pull_request: + branches: + - master + +jobs: + auto-merge: + runs-on: ubuntu-latest + steps: + - name: Automatically Merge PR + uses: pascalgn/automerge-action@v0.16.4 + env: + GITHUB_TOKEN: ${{ secrets.MY_PERSONAL_TOKEN }} + MERGE_METHOD: merge # or 'squash' or 'rebase' + MERGE_LABELS: "" diff --git a/.github/workflows/run_test.yml b/.github/workflows/create_pull_request.yml similarity index 60% rename from .github/workflows/run_test.yml rename to .github/workflows/create_pull_request.yml index d4d63c1..105cf0c 100644 --- a/.github/workflows/run_test.yml +++ b/.github/workflows/create_pull_request.yml @@ -3,7 +3,7 @@ name: Unit Tests on: push: branches: - - master + - dev jobs: test: @@ -60,3 +60,33 @@ jobs: run: | mkdir logs pytest -s + + create_pull_request: + runs-on: ubuntu-latest + needs: test # This creates the dependency link + if: github.actor == 'brianobot' + permissions: + contents: write + pull-requests: write + env: + GITHUB_TOKEN: ${{ secrets.MY_PERSONAL_TOKEN }} + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Create Pull Request + run: | + # Check if a PR already exists from dev to master + PR_EXISTS=$(gh pr list --head dev --base master --state open --json number -q '.[0].number') + + if [ -z "$PR_EXISTS" ]; then + echo "No open PR found. Creating a new one..." + gh pr create \ + --head dev \ + --base master \ + --title "Auto-PR: Dev to Master" \ + --body "Automated PR triggered by push from ${{ github.actor }}" \ + --assignee "${{ github.actor }}" + else + echo "PR already exists: #$PR_EXISTS. Skipping creation." + fi diff --git a/app/middlewares.py b/app/middlewares.py index 400fc94..a20409b 100644 --- a/app/middlewares.py +++ b/app/middlewares.py @@ -12,8 +12,8 @@ async def log_request_middleware(request: Request, call_next): log_dict = { "url": request.url.path, "method": request.method, - "process_time": f"{(time.time() - start):.2f}s", "status_code": response.status_code, + "process_time": f"{(time.time() - start):.2f}s", } logger.info(log_dict) diff --git a/app/models/tests/factories.py b/app/models/tests/factories.py index ef5fb10..33e3667 100644 --- a/app/models/tests/factories.py +++ b/app/models/tests/factories.py @@ -9,10 +9,10 @@ class UserFactory(factory.alchemy.SQLAlchemyModelFactory): - class Meta: + class Meta: # type: ignore model = UserDB sqlalchemy_session_factory = TestingSessionLocal sqlalchemy_session_persistence = "commit" - email = faker.email().lower() + email = factory.Faker("email") # type: ignore password = get_password_hash("password") diff --git a/app/routers/tests/conftest.py b/app/routers/tests/conftest.py index 5bff8a8..98e1903 100644 --- a/app/routers/tests/conftest.py +++ b/app/routers/tests/conftest.py @@ -8,7 +8,7 @@ @pytest.fixture -async def signup_data() -> dict: +async def signup_data() -> dict[str, str]: return { "email": faker.email(), "password": faker.password(length=8), diff --git a/app/routers/tests/test_auth.py b/app/routers/tests/test_auth.py index f9e2a22..92fba2d 100644 --- a/app/routers/tests/test_auth.py +++ b/app/routers/tests/test_auth.py @@ -3,6 +3,7 @@ from app.main import app from app.models import User as UserDB +from app.redis_manager import redis_manager from app.schemas.auth import UserModel @@ -63,7 +64,6 @@ async def sign_up_user(signup_data: dict): async def mutate_cache_item(key: str, value: dict): # to be used as a side effect to mutate cache item - from app.redis_manager import redis_manager redis_manager.cache_json_item(key, value) @@ -78,15 +78,19 @@ async def test_initiate_password_reset(client: AsyncClient, signup_data: dict): async def test_verify_reset_password_otp(client: AsyncClient, user: UserDB): - await mutate_cache_item(f"reset-code-{user.email}", {"code": "0000"}) - data = {"email": user.email, "code": "0000"} - response: Response = await client.post("/v1/auth/verify_password_reset", json=data) + # Seed the value to be validated against + redis_manager.cache_json_item(f"reset-code-{user.email}", {"code": "0000"}) + verification_data = {"email": user.email, "code": "0000"} + response: Response = await client.post( + "/v1/auth/verify_password_reset", json=verification_data + ) assert response.status_code == 200 - assert response.json().get("detail") == "Code is Correct" + assert response.json().get("detail") == "Verification is Successful" async def test_reset_password(client: AsyncClient, user: UserDB): - await mutate_cache_item(f"reset-code-{user.email}", {"code": "0000"}) + # Seed the value to be validated against + redis_manager.cache_json_item(f"reset-code-{user.email}", {"code": "0000"}) data = {"new_password": "password", "email": user.email, "code": "0000"} response: Response = await client.post("/v1/auth/reset_password", json=data) assert response.status_code == 200 @@ -94,7 +98,8 @@ async def test_reset_password(client: AsyncClient, user: UserDB): async def test_reset_password_fails(client: AsyncClient, user: UserDB): - await mutate_cache_item(f"reset-code-{user.email}", {"code": "0000"}) + # Seed the value to be validated against + redis_manager.cache_json_item(f"reset-code-{user.email}", {"code": "0000"}) data = {"new_password": "password", "email": user.email, "code": "1111"} response: Response = await client.post("/v1/auth/reset_password", json=data) assert response.status_code == 400 @@ -146,7 +151,8 @@ async def test_logout(client: AsyncClient, auth_header: dict[str, str]): async def test_get_user_detail( - client: AsyncClient, user: UserDB, auth_header: dict[str, str] + client: AsyncClient, + auth_header: dict[str, str], ): response: Response = await client.get("/v1/auth/me", headers=auth_header) assert response.status_code == 200 diff --git a/app/services/auth.py b/app/services/auth.py index 7bb41c7..5ae6087 100644 --- a/app/services/auth.py +++ b/app/services/auth.py @@ -159,7 +159,7 @@ async def verify_reset_password_otp(code: str, email: str, session: AsyncSession if not user: raise HTTPException(status_code=400, detail="Invalid Reset Code") - return {"detail": "Code is Correct"} + return {"detail": "Verification is Successful"} async def reset_password( diff --git a/conftest.py b/conftest.py index 8e9e2ff..9d281b6 100644 --- a/conftest.py +++ b/conftest.py @@ -77,6 +77,7 @@ async def user(session: AsyncSession): session.add(user) await session.commit() await session.refresh(user) + await session.flush() return user