Skip to content

Commit f8888e3

Browse files
authored
Add Psalm security checks (has_quotes only) and fix detected issues
* Add Psalm security checks (`has_quotes` only) * Fix detected issues * Add psalm command to makefile and test execution script
1 parent 6894b7b commit f8888e3

40 files changed

+1801
-213
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: "Security scan"
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
workflow_dispatch:
9+
10+
concurrency:
11+
group: "${{ github.workflow }}-${{ github.ref }}"
12+
cancel-in-progress: true
13+
14+
jobs:
15+
security-scan:
16+
name: "Security scan"
17+
runs-on: "ubuntu-latest"
18+
env:
19+
COMPOSE_FILE: ".github/actions/docker-compose-app.yml"
20+
APPLICATION_ROOT: "${{ github.workspace }}"
21+
PHP_IMAGE: "githubactions-php-apache:8.4"
22+
UPDATE_FILES_ACL: true
23+
steps:
24+
- name: "Set env"
25+
run: |
26+
echo "APP_CONTAINER_HOME=${{ runner.temp }}/app_home" >> $GITHUB_ENV
27+
- name: "Checkout"
28+
uses: "actions/checkout@v4"
29+
- name: "Restore dependencies cache"
30+
uses: actions/cache@v4
31+
with:
32+
path: |
33+
${{ env.APP_CONTAINER_HOME }}/.composer/cache/
34+
${{ env.APP_CONTAINER_HOME }}/.npm/_cacache/
35+
key: "app_home_deps-${{ matrix.php-version }}-${{ hashFiles('composer.lock', 'package-lock.json') }}"
36+
restore-keys: |
37+
app_home_deps-${{ matrix.php-version }}-
38+
app_home_deps-
39+
- name: "Initialize containers"
40+
run: |
41+
.github/actions/init_containers-start.sh
42+
- name: "Show versions"
43+
run: |
44+
.github/actions/init_show-versions.sh
45+
- name: "Build dependencies / translations"
46+
run: |
47+
docker compose exec -T app .github/actions/init_build.sh
48+
- name: "Psalm security scan"
49+
run: |
50+
docker compose exec -T app vendor/bin/psalm --long-progress --output-format=github

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ phpstan-generate-baseline: c=--generate-baseline=.phpstan-baseline.php analyze
149149
phpstan-generate-baseline: phpstan
150150
.PHONY: phpstan-generate-baseline
151151

152+
psalm: ## Run psalm analysis
153+
@$(eval c ?=)
154+
@$(PHP) php vendor/bin/psalm $(c)
155+
.PHONY: psalm
156+
152157
## —— Coding standards —————————————————————————————————————————————————————————
153158
phpcsfixer-check: ## Check for php coding standards issues
154159
@$(PHP) vendor/bin/php-cs-fixer check --diff -vvv

ajax/asset/assetdefinition.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,17 @@
5454
$v['id'] = $k;
5555
$field_results[] = $v;
5656
}
57-
echo json_encode([
57+
58+
/**
59+
* Safe JSON response.
60+
* @psalm-taint-escape has_quotes
61+
*/
62+
$response = json_encode([
5863
'results' => $field_results,
5964
'count' => count($all_fields),
6065
], JSON_THROW_ON_ERROR);
66+
67+
echo $response;
6168
return;
6269
} elseif ($_REQUEST['action'] === 'get_core_field_editor') {
6370
header("Content-Type: text/html; charset=UTF-8");

ajax/dashboard.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,14 @@
151151
throw new AccessDeniedHttpException();
152152
}
153153

154-
echo $dashboard->getFilter(); // `Dashboard::getFilter()` already returns a JSON encoded string.
154+
/**
155+
* `Dashboard::getFilter()` already returns a JSON encoded string.
156+
*
157+
* @psalm-taint-escape has_quotes
158+
*/
159+
$filter = $dashboard->getFilter();
160+
161+
echo $filter;
155162
return;
156163
}
157164

ajax/getDropdownNumber.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,10 @@
4040
header("Content-Type: application/json; charset=UTF-8");
4141
Html::header_nocache();
4242

43-
echo Dropdown::getDropdownNumber($_POST);
43+
/**
44+
* Safe JSON response.
45+
* @psalm-taint-escape has_quotes
46+
*/
47+
$response = Dropdown::getDropdownNumber($_POST, json: true);
48+
49+
echo $response;

ajax/getDropdownUsers.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,10 @@
4040
header("Content-Type: application/json; charset=UTF-8");
4141
Html::header_nocache();
4242

43-
echo Dropdown::getDropdownUsers($_POST);
43+
/**
44+
* Safe JSON response.
45+
* @psalm-taint-escape has_quotes
46+
*/
47+
$response = Dropdown::getDropdownUsers($_POST, json: true);
48+
49+
echo $response;

ajax/getDropdownValue.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,10 @@
4040
header("Content-Type: application/json; charset=UTF-8");
4141
Html::header_nocache();
4242

43-
echo Dropdown::getDropdownValue($_POST);
43+
/**
44+
* Safe JSON response.
45+
* @psalm-taint-escape has_quotes
46+
*/
47+
$response = Dropdown::getDropdownValue($_POST, json: true);
48+
49+
echo $response;

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@
124124
"symfony/twig-bundle": "^6.4",
125125
"symfony/var-dumper": "^6.4",
126126
"symfony/web-profiler-bundle": "^6.4",
127-
"thecodingmachine/phpstan-safe-rule": "^1.4"
127+
"thecodingmachine/phpstan-safe-rule": "^1.4",
128+
"vimeo/psalm": "^6.13"
128129
},
129130
"provide": {
130131
"ext-sodium": "*"

0 commit comments

Comments
 (0)