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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
- name: Validate STAR/AIWA compliance
run: |
pnpm run i18n-check
grep -q "WordPress.*6\.4" starmus-audio-recorder.php || echo "⚠️ WordPress 6.4+ requirement not found"
grep -q "WordPress.*6\.9" starmus-audio-recorder.php || echo "⚠️ WordPress 6.9+ requirement not found"
grep -r "star-" src/ || echo "⚠️ STAR prefix not found in source"

- name: Run static analysis
Expand Down Expand Up @@ -106,7 +106,7 @@ jobs:
run: pnpm run test:wp-env

- name: Stop WordPress test environment
run: pnpm run env:stop
run: pnpm run env:stop || true

- name: Install Playwright
run: pnpm exec playwright install --with-deps chromium
Expand Down
58 changes: 31 additions & 27 deletions .github/workflows/ethicalcheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,42 +28,46 @@

name: EthicalCheck-Workflow

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
# Customize trigger events based on your DevSecOps processes.
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
Comment on lines -35 to -38

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

5. Merges skip api security scans 🐞 Bug ⛨ Security

The workflow's on block removes the push and pull_request events and retains only a weekly
schedule and manual dispatch. Even when all three APIsec settings are configured, API changes can
therefore enter the main branch without invoking this scan and are examined only during a later
scheduled run.
Agent Prompt
## Issue description
The repaired API security workflow no longer runs on pushes or pull requests because both event triggers were removed. Restore appropriate change-triggered execution while retaining the existing configuration gate so unconfigured repositories and forked pull requests skip cleanly.

## Issue Context
The previous workflow targeted pushes and pull requests to `main`. The new weekly schedule can complement those triggers but does not scan each update before or when it reaches the main branch.

## Fix Focus Areas
- .github/workflows/ethicalcheck.yml[31-34]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@copilot - ## Issue description
The repaired API security workflow no longer runs on pushes or pull requests because both event triggers were removed. Restore appropriate change-triggered execution while retaining the existing configuration gate so unconfigured repositories and forked pull requests skip cleanly.

Issue Context

The previous workflow targeted pushes and pull requests to main. The new weekly schedule can complement those triggers but does not scan each update before or when it reaches the main branch.

Fix Focus Areas

  • .github/workflows/ethicalcheck.yml[31-34]

schedule:
- cron: '37 9 * * 2'

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

Comment on lines 31 to 35
permissions:
contents: read

jobs:
Trigger_EthicalCheck:
permissions:
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
trigger_ethicalcheck:
runs-on: ubuntu-latest
env:
APISEC_BASE_URL: ${{ vars.APISEC_BASE_URL }}
APISEC_SPECIFICATION_PATH: ${{ vars.APISEC_SPECIFICATION_PATH }}
APISECU_TOKEN: ${{ secrets.APISECU_TOKEN }}

steps:
- name: EthicalCheck Free & Automated API Security Testing Service
uses: apisec-inc/ethicalcheck-action@005fac321dd843682b1af6b72f30caaf9952c641
with:
# The OpenAPI Specification URL or Swagger Path or Public Postman collection URL.
oas-url: "http://netbanking.apisec.ai:8080/v2/api-docs"
# The email address to which the penetration test report will be sent.
email: "xxx@apisec.ai"
sarif-result-file: "ethicalcheck-results.sarif"

- name: Upload sarif file to repository
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ./ethicalcheck-results.sarif

- name: Checkout code
uses: actions/checkout@v4

- name: Validate EthicalCheck configuration
id: config
run: |
if [ -z "${APISEC_BASE_URL}" ] || [ -z "${APISEC_SPECIFICATION_PATH}" ] || [ -z "${APISECU_TOKEN}" ]; then
echo "configured=false" >> "${GITHUB_OUTPUT}"
echo "ℹ️ EthicalCheck is not configured. Set APISEC_BASE_URL, APISEC_SPECIFICATION_PATH, and APISECU_TOKEN to enable scans."
exit 0
fi

if [ ! -f "${APISEC_SPECIFICATION_PATH}" ]; then
echo "Configured OpenAPI specification file not found: ${APISEC_SPECIFICATION_PATH}"
exit 1
fi

echo "configured=true" >> "${GITHUB_OUTPUT}"

- name: Run APIsec scan
if: steps.config.outputs.configured == 'true'
uses: apisec-university/free-API-security-test-action@beta

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. A mutable action can expose scan secrets 🐞 Bug ⛨ Security

The Run APIsec scan step references the third-party action through the movable beta tag while
passing it APISECU_TOKEN. If that tag is moved or its repository is compromised, scheduled and
manually dispatched jobs execute the replacement code with the APIsec credential and read access to
the repository.
Agent Prompt
## Issue description
The APIsec workflow invokes a third-party action through the mutable `beta` tag while exposing `APISECU_TOKEN` to that action. Pin the action to a reviewed full-length commit SHA so later tag movement cannot silently change the code that receives the credential.

## Issue Context
The replaced EthicalCheck action was pinned to a full commit SHA, and other third-party workflows in this repository follow the same pattern. Preserve the action inputs and configuration gate while replacing only the mutable reference.

## Fix Focus Areas
- .github/workflows/ethicalcheck.yml[67-73]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@copilot - ## Issue description
The APIsec workflow invokes a third-party action through the mutable beta tag while exposing APISECU_TOKEN to that action. Pin the action to a reviewed full-length commit SHA so later tag movement cannot silently change the code that receives the credential.

Issue Context

The replaced EthicalCheck action was pinned to a full commit SHA, and other third-party workflows in this repository follow the same pattern. Preserve the action inputs and configuration gate while replacing only the mutable reference.

Fix Focus Areas

  • .github/workflows/ethicalcheck.yml[67-73]

with:
Comment on lines +67 to +70
base_url: ${{ env.APISEC_BASE_URL }}
specification_path: ${{ env.APISEC_SPECIFICATION_PATH }}
apisecu_token: ${{ env.APISECU_TOKEN }}
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
php: ["8.2", "8.3", "8.4"]
wordpress: ["6.8", "6.9"]
wordpress: ["6.9", "trunk"]

Comment on lines 16 to 20
steps:
- name: Checkout code
Expand Down Expand Up @@ -57,7 +57,7 @@ jobs:
pnpm run test:e2e

- name: Stop WordPress
run: pnpm run env:stop
run: pnpm run env:stop || true
if: always()

security-scan:
Expand Down
2 changes: 1 addition & 1 deletion .wp-env.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"core": "WordPress/WordPress#6.4",
"core": "WordPress/WordPress#6.9",
"phpVersion": "8.2",
"plugins": ["."],
"themes": ["https://downloads.wordpress.org/theme/twentytwentyfour.1.0.zip"],
Expand Down
2 changes: 1 addition & 1 deletion scripts/validate-build.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const fs = require('fs');
console.log("🔍 Validating build configuration...\n");

const requiredFiles = [
'src/css/starmus-audio-recorder-style.css',
'src/css/starmus-audio-recorder.css',
'src/js/starmus-audio-editor.js',
'src/js/starmus-core.js',
'src/js/starmus-hooks.js',
Expand Down
21 changes: 19 additions & 2 deletions src/core/StarmusAssetLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -453,19 +453,20 @@ private function resolve_bootstrap_mode(): string
private function build_runtime_bootstrap_base(array $config): array
{
$runtime_projection = $this->package_resolver->get_runtime_projection();
$recording_id = $this->resolve_runtime_recording_id();

return [
'version' => $this->resolve_version(),
'config' => $config,
'env' => wp_get_environment_type(),
'recordingId' => isset(self::$editor_data['post_id']) ? (int) self::$editor_data['post_id'] : 0,
'recordingId' => $recording_id,
'restUrl' => esc_url_raw(rest_url()),
'homeUrl' => esc_url_raw(home_url('/')),
'pageType' => 'unknown',
'mode' => $this->resolve_bootstrap_mode(),
'artifact' => [
'type' => $runtime_projection['artifactType'] ?? 'OralRuntimeArtifact',
'id' => isset(self::$editor_data['post_id']) ? (string) self::$editor_data['post_id'] : '',
'id' => $recording_id > 0 ? (string) $recording_id : '',
],
'runtime' => [
'eventSchemaId' => $runtime_projection['eventSchemaId'] ?? 'starmus.oral-runtime-event',
Expand All @@ -484,6 +485,22 @@ private function build_runtime_bootstrap_base(array $config): array
];
}

private function resolve_runtime_recording_id(): int
{
if (isset(self::$editor_data['post_id'])) {
return (int) self::$editor_data['post_id'];
}

$recording_id = filter_input(
INPUT_GET,
'starmus_recording_id',
FILTER_VALIDATE_INT,
['options' => ['min_range' => 1]]
);

return \is_int($recording_id) ? $recording_id : 0;
}

/**
* @param array<string, mixed> $config
*
Expand Down
6 changes: 5 additions & 1 deletion src/js/starmus-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ function getRuntimeBootstrap() {
// STARMUS_BOOTSTRAP is composed by PHP via wp_add_inline_script(..., 'before')
// immediately before this bundle executes, so the merged object is the
// authoritative runtime contract for initialization.
if (!window.STARMUS_BOOTSTRAP || typeof window.STARMUS_BOOTSTRAP !== "object") {
if (
typeof window === "undefined" ||
!window.STARMUS_BOOTSTRAP ||
typeof window.STARMUS_BOOTSTRAP !== "object"
) {
console.warn("[StarmusMain] Missing STARMUS_BOOTSTRAP.");
return null;
}
Expand Down
31 changes: 22 additions & 9 deletions src/services/StarmusR2DirectService.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,15 +246,7 @@ private function configureR2(): void
throw new RuntimeException('STARMUS_R2_SECRET_KEY is not defined or is empty.');
}

if (! \defined('STARMUS_R2_ENDPOINT')) {
throw new RuntimeException('STARMUS_R2_ENDPOINT is not defined or is empty.');
}
// Read via constant() so static analysis cannot infer the literal value; this
// preserves the empty-string guard when wp-config.php defines the constant as ''.
$r2_endpoint = (string) \constant('STARMUS_R2_ENDPOINT');
if (trim($r2_endpoint) === '') {
throw new RuntimeException('STARMUS_R2_ENDPOINT is not defined or is empty.');
}
$r2_endpoint = $this->getRequiredStringConstant('STARMUS_R2_ENDPOINT');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

3. Reviewers must assess unrelated fixes 📘 Rule violation ⚙ Maintainability

The PR combines workflow runtime changes, an API security action replacement, build-validator
repair, broad JavaScript formatting, and an R2 constant-loading refactor in one change set. Because
the workflow, validator, formatting, and PHP groups can be removed independently without making the
others incoherent, reviewers must validate several unrelated failure modes together.
Agent Prompt
## Issue description
The pull request contains several independently removable fixes rather than one feature or bug-fix change set.

## Issue Context
Separate workflow/runtime repair, APIsec workflow replacement, build validation, formatting-only changes, and PHP constant handling into focused pull requests with their relevant tests.

## Fix Focus Areas
- .github/workflows/ci.yml[60-63]
- .github/workflows/ethicalcheck.yml[51-73]
- scripts/validate-build.cjs[6-10]
- src/services/StarmusR2DirectService.php[249-249]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@copilot - ## Issue description
The pull request contains several independently removable fixes rather than one feature or bug-fix change set.

Issue Context

Separate workflow/runtime repair, APIsec workflow replacement, build validation, formatting-only changes, and PHP constant handling into focused pull requests with their relevant tests.

Fix Focus Areas

  • .github/workflows/ci.yml[60-63]
  • .github/workflows/ethicalcheck.yml[51-73]
  • scripts/validate-build.cjs[6-10]
  • src/services/StarmusR2DirectService.php[249-249]


$this->bucket = \defined('STARMUS_R2_BUCKET') ? STARMUS_R2_BUCKET : 'starmus-audio';
$account_id = STARMUS_R2_ACCOUNT_ID;
Expand Down Expand Up @@ -301,6 +293,27 @@ private function configureAws(): void
]);
}

private function getRequiredStringConstant(string $constant_name): string
{
Comment on lines +296 to +297

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Maintainers inherit conflicting styles 📘 Rule violation ⚙ Maintainability

getRequiredStringConstant() uses a camelCase method name and a PSR-style next-line opening brace
in WordPress-integrated source, with no inline waiver. When the repository's WordPress naming and
core rules scan src/, this newly added helper conflicts with the preferred style and gives later
additions two conventions to follow.
Agent Prompt
## Issue description
The new helper follows PSR naming and brace placement instead of the repository's preferred WordPress coding style.

## Issue Context
Rename the helper and its call site using WordPress snake_case, and place the opening brace according to the applicable WordPress standard. Update any references consistently.

## Fix Focus Areas
- src/services/StarmusR2DirectService.php[249-249]
- src/services/StarmusR2DirectService.php[296-315]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@copilot - ## Issue description
The new helper follows PSR naming and brace placement instead of the repository's preferred WordPress coding style.

Issue Context

Rename the helper and its call site using WordPress snake_case, and place the opening brace according to the applicable WordPress standard. Update any references consistently.

Fix Focus Areas

  • src/services/StarmusR2DirectService.php[249-249]
  • src/services/StarmusR2DirectService.php[296-315]

if (! \defined($constant_name)) {
throw new RuntimeException(\sprintf('%s is not defined or is empty.', $constant_name));
}

Comment on lines +298 to +301

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

2. Php changes can merge without tests 📘 Rule violation ▣ Testability

getRequiredStringConstant() adds validation behavior, but the changed workflows run PHP static
analysis and WordPress activation or end-to-end checks without invoking the configured PHPUnit
suite. When endpoint constants are undefined, non-scalar, or empty, no required CI job exercises
those branches, so a regression in the new helper can merge undetected.
Agent Prompt
## Issue description
The PR adds PHP validation branches without a required CI invocation of the configured PHPUnit suite.

## Issue Context
Add a blocking PHP unit-test step and cover undefined, non-scalar, empty, and valid string constants. Keep the existing static-analysis step blocking.

## Fix Focus Areas
- src/services/StarmusR2DirectService.php[296-315]
- .github/workflows/ci.yml[66-72]
- .github/workflows/test.yml[41-57]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@copilot - ## Issue description
The PR adds PHP validation branches without a required CI invocation of the configured PHPUnit suite.

Issue Context

Add a blocking PHP unit-test step and cover undefined, non-scalar, empty, and valid string constants. Keep the existing static-analysis step blocking.

Fix Focus Areas

  • src/services/StarmusR2DirectService.php[296-315]
  • .github/workflows/ci.yml[66-72]
  • .github/workflows/test.yml[41-57]

$constant_value = \constant($constant_name);

if (! \is_scalar($constant_value)) {
throw new RuntimeException(\sprintf('%s is not defined or is empty.', $constant_name));
}

$resolved_value = (string) $constant_value;

if ($resolved_value === '') {
throw new RuntimeException(\sprintf('%s is not defined or is empty.', $constant_name));
}

return $resolved_value;
}
Comment on lines +296 to +315
Comment on lines +308 to +315

private function createOptimizedVersion(string $input, array $params): ?string
{
$temp_file = tempnam(sys_get_temp_dir(), 'starmus_africa_') . '.mp3';
Expand Down