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
160 changes: 160 additions & 0 deletions .github/workflows/l5-swagger-generate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
name: OpenAPI generation

on:
push:
pull_request:
jobs:
openapi-generate:
runs-on: ubuntu-latest
env:
APP_ENV: testing
APP_DEBUG: true
APP_KEY: base64:4vh0op/S1dAsXKQ2bbdCfWRyCI9r8NNIdPXyZWt9PX4=
DEV_EMAIL_TO: smarcet@gmail.com
APP_URL: http://localhost
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: idp_test
DB_USERNAME: root
DB_PASSWORD: 1qaz2wsx
REDIS_HOST: 127.0.0.1
REDIS_PORT: 6379
REDIS_DB: 0
REDIS_PASSWORD: 1qaz2wsx
REDIS_DATABASES: 16
Comment on lines +12 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid committing credential-like and PII values in workflow env.

APP_KEY, DB_PASSWORD, REDIS_PASSWORD, and DEV_EMAIL_TO are committed directly in repo. Even for CI/test values, this weakens security posture and can trigger secret/PII leakage concerns.

Suggested hardening
-            APP_KEY: base64:4vh0op/S1dAsXKQ2bbdCfWRyCI9r8NNIdPXyZWt9PX4=
-            DEV_EMAIL_TO: smarcet@gmail.com
+            APP_KEY: ${{ secrets.CI_APP_KEY }}
+            DEV_EMAIL_TO: ${{ vars.DEV_EMAIL_TO }}
...
-            DB_PASSWORD: 1qaz2wsx
+            DB_PASSWORD: ${{ secrets.CI_DB_PASSWORD }}
...
-            REDIS_PASSWORD: 1qaz2wsx
+            REDIS_PASSWORD: ${{ secrets.CI_REDIS_PASSWORD }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
APP_KEY: base64:4vh0op/S1dAsXKQ2bbdCfWRyCI9r8NNIdPXyZWt9PX4=
DEV_EMAIL_TO: smarcet@gmail.com
APP_URL: http://localhost
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: idp_test
DB_USERNAME: root
DB_PASSWORD: 1qaz2wsx
REDIS_HOST: 127.0.0.1
REDIS_PORT: 6379
REDIS_DB: 0
REDIS_PASSWORD: 1qaz2wsx
REDIS_DATABASES: 16
APP_KEY: ${{ secrets.CI_APP_KEY }}
DEV_EMAIL_TO: ${{ vars.DEV_EMAIL_TO }}
APP_URL: http://localhost
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: idp_test
DB_USERNAME: root
DB_PASSWORD: ${{ secrets.CI_DB_PASSWORD }}
REDIS_HOST: 127.0.0.1
REDIS_PORT: 6379
REDIS_DB: 0
REDIS_PASSWORD: ${{ secrets.CI_REDIS_PASSWORD }}
REDIS_DATABASES: 16
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/l5-swagger-generate.yml around lines 12 - 25, Replace
hardcoded credential-like and PII environment values in the workflow by removing
the literal values for APP_KEY, DB_PASSWORD, REDIS_PASSWORD, and DEV_EMAIL_TO
(and any other secret-like envs such as DB_USERNAME if applicable) and instead
load them from GitHub Actions secrets (e.g., APP_KEY: ${{ secrets.APP_KEY }},
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}, REDIS_PASSWORD: ${{
secrets.REDIS_PASSWORD }}, DEV_EMAIL_TO: ${{ secrets.DEV_EMAIL_TO }}). Ensure
the workflow uses non-sensitive defaults or placeholders for local-only settings
(e.g., DB_HOST, DB_PORT) and do not commit real secrets; after updating, rotate
any credentials already committed.

SSL_ENABLED: false
SESSION_DRIVER: redis
PHP_VERSION: 8.3
OTEL_SDK_DISABLED: true
OTEL_SERVICE_ENABLED: false

services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: ${{env.DB_PASSWORD}}
MYSQL_DATABASE: ${{env.DB_DATABASE}}
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Create Redis
uses: supercharge/redis-github-action@1.8.1
with:
redis-port: ${{env.REDIS_PORT}}
redis-password: ${{env.REDIS_PASSWORD}}

- name: Check out repository code
uses: actions/checkout@v4

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ env.PHP_VERSION }}
extensions: pdo_mysql, mbstring, exif, pcntl, bcmath, sockets, gettext, apcu, redis, igbinary, memcached

- name: Install dependencies
uses: "ramsey/composer-install@v3"
env:
COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.PAT }}"} }'

Comment on lines +59 to +61
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/l5-swagger-generate.yml

Repository: OpenStackweb/openstackid

Length of output: 6964


🏁 Script executed:

# Check if PAT secret is referenced elsewhere in workflows
rg 'secrets\.PAT' .github/workflows/

# Check for any repository secrets documentation or configuration
find .github -name "*.yml" -o -name "*.yaml" | head -20

Repository: OpenStackweb/openstackid

Length of output: 720


🏁 Script executed:

# Check pull_request_unit_tests.yml to see if it has guards against fork PRs
cat -n .github/workflows/pull_request_unit_tests.yml | head -40

Repository: OpenStackweb/openstackid

Length of output: 1503


🏁 Script executed:

# Search for composer-install and secrets.PAT in pull_request_unit_tests.yml
cat -n .github/workflows/pull_request_unit_tests.yml | grep -A 3 -B 3 "secrets.PAT"

Repository: OpenStackweb/openstackid

Length of output: 362


🏁 Script executed:

# Check if there are any conditional guards in the openapi-generate job
cat -n .github/workflows/l5-swagger-generate.yml | grep -A 10 "openapi-generate:"

Repository: OpenStackweb/openstackid

Length of output: 512


🏁 Script executed:

# Check for composer.json to see if there are private package dependencies
head -50 composer.json | grep -A 5 -B 5 '"repositories"'

Repository: OpenStackweb/openstackid

Length of output: 245


🏁 Script executed:

# Let's check what happens when secrets.PAT is undefined in GitHub Actions
# Also verify the behavior described in GitHub documentation by searching for any conditional patterns in the repo
rg 'github\.event\.pull_request\.head\.repo\.full_name' .github/workflows/

Repository: OpenStackweb/openstackid

Length of output: 50


secrets.PAT on fork PRs will cause dependency installation to fail.

Repository secrets are unavailable by default on forked pull requests. When secrets.PAT is undefined, Composer authentication fails and blocks the workflow, especially problematic since composer.json includes a private VCS dependency (github.com/smarcet/recaptcha).

To fix this, either:

  • Replace secrets.PAT with github.token (note: may not access private packages with restricted scope)
  • Or gate this workflow to same-repo PRs only if the PAT's broader scope is required
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/l5-swagger-generate.yml around lines 63 - 65, The workflow
currently injects COMPOSER_AUTH using secrets.PAT which is unavailable for
forked PRs and breaks composer install for the private VCS dependency referenced
in composer.json (github.com/smarcet/recaptcha); update the env setting for
COMPOSER_AUTH to use github.token instead (COMPOSER_AUTH -> '{"github-oauth":
{"github.com": "${{ github.token }}"} }') if that scope suffices, or else gate
this job to run only for same-repo PRs (i.e., only allow runs where the PR
originates from the same repository) so the PAT from secrets.PAT is available
for installing the private dependency.

- name: Generate OpenAPI docs
run: php artisan l5-swagger:generate

- name: Build Swagger UI preview
run: |
mkdir -p swagger-ui
cp storage/api-docs/api-docs.json swagger-ui/api-docs.json
cat > swagger-ui/index.html << 'HTMLEOF'
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>OpenStackID API - Swagger UI</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist/swagger-ui.css" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
<script>
window.onload = () => {
window.ui = SwaggerUIBundle({
url: 'api-docs.json',
dom_id: '#swagger-ui'
});
};
</script>
</body>
</html>
HTMLEOF

- name: Upload Swagger UI artifact
uses: actions/upload-artifact@v4
with:
name: swagger-ui
path: swagger-ui/
if-no-files-found: error

pages-preview:
name: Publish Swagger UI to GitHub Pages
needs: openapi-generate
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest

permissions:
contents: write
issues: write
pull-requests: write

Comment on lines +102 to +109
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat .github/workflows/l5-swagger-generate.yml

Repository: OpenStackweb/openstackid

Length of output: 5844


Guard pages-preview job from fork PRs to prevent permission failures.

The job writes to gh-pages and comments on PRs. On fork PRs, the GITHUB_TOKEN has restricted permissions, causing these operations to fail noisily. The job needs to skip execution for fork PRs.

Suggested condition
-        if: github.event_name == 'pull_request'
+        if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/l5-swagger-generate.yml around lines 106 - 113, The
pages-preview job should skip on forked PRs to avoid failing operations that
require full GITHUB_TOKEN permissions; add an extra job-level if condition to
only run when the PR's head repo matches the base repository (e.g., compare
github.event.pull_request.head.repo.full_name to github.repository or compare
github.event.pull_request.head.repo.owner to github.repository_owner) so the job
(pages-preview) is skipped for forked pull requests.

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Download Swagger UI artifact
uses: actions/download-artifact@v4
with:
name: swagger-ui
path: swagger-ui

- name: Build public directory for GitHub Pages
run: |
PR_PATH="openapi/pr-${{ github.event.number }}"
mkdir -p "public/${PR_PATH}"
cp -R swagger-ui/* "public/${PR_PATH}/"
echo "Built GitHub Pages content at public/${PR_PATH}"

- name: Publish to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
keep_files: true

- name: Comment preview URL on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.pull_request.number;
const owner = context.repo.owner;
const repo = context.repo.repo;
const baseUrl = `https://${owner}.github.io/${repo}`;
const previewPath = `/openapi/pr-${prNumber}/`;
const url = `${baseUrl}${previewPath}`;

const body = [
'📘 **OpenAPI / Swagger preview**',
'',
`➡️ ${url}`,
'',
'This page is automatically updated on each push to this PR.'
].join('\n');

await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body,
});

11 changes: 9 additions & 2 deletions app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -342,14 +342,17 @@ public function get($id)
#[OA\Get(
path: '/api/v2/users/{id}',
summary: 'Get a user by ID',
description: 'Get a user by ID (only for accounts of type "SERVICE")',
description: 'Retrieves user details by their numeric ID.',
operationId: 'getUserByIdV2',
tags: ['Users'],
tags: ['Users', 'V2'],
security: [
['OAuth2UserSecurity' => [
IUserScopes::ReadAll,
]],
],
x: [
'x-required-client-type' => 'SERVICE',
],
parameters: [
new OA\Parameter(
name: 'id',
Expand Down Expand Up @@ -380,6 +383,10 @@ public function get($id)
response: HttpResponse::HTTP_INTERNAL_SERVER_ERROR,
description: 'Server Error'
),
new OA\Response(
response: HttpResponse::HTTP_FORBIDDEN,
description: 'Forbidden - Only service accounts are allowed'
),
]
)]
public function getV2($id)
Expand Down
Loading