Skip to content

Commit 94945a2

Browse files
committed
Refactor auth and DTO helpers and simplify Snyk workflow
1 parent f356d72 commit 94945a2

15 files changed

Lines changed: 581 additions & 102 deletions
Lines changed: 9 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,19 @@
1-
# This workflow uses actions that are not certified by GitHub.
2-
# They are provided by a third-party and are governed by
3-
# separate terms of service, privacy policy, and support
4-
# documentation.
1+
name: Snyk Scan
52

6-
# A sample workflow which sets up Snyk to analyze the full Snyk platform (Snyk Open Source, Snyk Code,
7-
# Snyk Container and Snyk Infrastructure as Code)
8-
# The setup installs the Snyk CLI - for more details on the possible commands
9-
# check https://docs.snyk.io/snyk-cli/cli-reference
10-
# The results of Snyk Code are then uploaded to GitHub Security Code Scanning
11-
#
12-
# In order to use the Snyk Action you will need to have a Snyk API token.
13-
# More details in https://github.com/snyk/actions#getting-your-snyk-token
14-
# or you can signup for free at https://snyk.io/login
15-
#
16-
# For more examples, including how to limit scans to only high-severity issues
17-
# and fail PR checks, see https://github.com/snyk/actions/
18-
19-
name: Snyk Security
20-
21-
on:
22-
push:
23-
branches: ["master" ]
24-
pull_request:
25-
branches: ["master"]
26-
27-
permissions:
28-
contents: read
3+
on: [push, pull_request]
294

305
jobs:
316
snyk:
32-
permissions:
33-
contents: read
34-
security-events: write
35-
actions: read
367
runs-on: ubuntu-latest
37-
env:
38-
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
8+
399
steps:
4010
- uses: actions/checkout@v4
41-
- name: Set up Snyk CLI to check for security issues
42-
uses: snyk/actions/setup@806182742461562b67788a64410098c9d9b96adb
43-
44-
- name: Snyk Code test
45-
run: snyk code test --sarif > snyk-code.sarif
46-
47-
- name: Snyk Open Source monitor
48-
run: snyk monitor --all-projects
49-
50-
- name: Snyk IaC test and report
51-
run: snyk iac test --report
5211

53-
- name: Build a Docker image
54-
run: docker build -t your/image-to-test .
12+
- name: Install Snyk
13+
run: npm install -g snyk
5514

56-
- name: Snyk Container monitor
57-
run: snyk container monitor your/image-to-test --file=Dockerfile
15+
- name: Authenticate Snyk
16+
run: snyk auth ${{ secrets.SNYK_TOKEN }}
5817

59-
- name: Upload result to GitHub Code Scanning
60-
uses: github/codeql-action/upload-sarif@v3
61-
with:
62-
sarif_file: snyk-code.sarif
18+
- name: Run Snyk Code
19+
run: snyk code test --sarif > snyk-code.sarif

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# PSFS Core
1+
# Php Simple Fast and Secure
2+
## PSFS Core
23

34
[![Build Status](https://scrutinizer-ci.com/g/psfs/core/badges/build.png?b=master)](https://scrutinizer-ci.com/g/psfs/core/build-status/master)
45
[![Security Pipeline](https://github.com/psfs/core/actions/workflows/security-pipeline.yml/badge.svg)](https://github.com/psfs/core/actions/workflows/security-pipeline.yml)

src/base/types/AuthController.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PSFS\base\exception\AccessDeniedException;
66
use PSFS\base\exception\UserAuthException;
77
use PSFS\base\types\interfaces\AuthInterface;
8+
use PSFS\base\types\traits\LoggedGuardTrait;
89
use PSFS\base\types\traits\SecureTrait;
910

1011
/**
@@ -13,16 +14,19 @@
1314
abstract class AuthController extends Controller implements AuthInterface
1415
{
1516
use SecureTrait;
17+
use LoggedGuardTrait;
1618

1719
/**
1820
* @throws AccessDeniedException|UserAuthException
1921
*/
2022
public function init()
2123
{
2224
parent::init();
23-
if (!$this->isLogged()) {
24-
throw new UserAuthException(t("User not logged in"));
25-
}
25+
$this->assertUserLoggedIn();
2626
}
2727

28+
protected function assertUserLoggedIn(): void
29+
{
30+
$this->ensureLoggedOrThrow(new UserAuthException(t("User not logged in")));
31+
}
2832
}

src/base/types/Controller.php

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,8 @@ abstract class Controller extends Singleton implements ControllerInterface
3838
*/
3939
public function render($template, array $vars = array(), $cookies = array(), $domain = null)
4040
{
41-
$vars['__menu__'] = $this->getMenu();
42-
if (Config::getParam('profiling.enable')) {
43-
$vars['__profiling__'] = Inspector::getStats();
44-
}
45-
$domain = (null === $domain) ? $this->getDomain() : $domain;
41+
$domain = $this->resolveRenderDomain($domain);
42+
$vars = $this->buildTemplateVars($vars, true);
4643
return $this->tpl->render($domain . $template, $vars, $cookies);
4744
}
4845

@@ -70,8 +67,8 @@ public function init()
7067
*/
7168
public function dump($template, array $vars = array(), $domain = null)
7269
{
73-
$vars['__menu__'] = $this->getMenu();
74-
$domain = $domain ?: $this->getDomain();
70+
$vars = $this->buildTemplateVars($vars, false);
71+
$domain = $this->resolveRenderDomain($domain);
7572
return $this->tpl->dump($domain . $template, $vars);
7673
}
7774

@@ -104,4 +101,19 @@ public function getDomain()
104101
return "@{$this->domain}/";
105102
}
106103

104+
private function resolveRenderDomain(?string $domain): string
105+
{
106+
return $domain ?? $this->getDomain();
107+
}
108+
109+
private function buildTemplateVars(array $vars, bool $includeProfiling): array
110+
{
111+
$vars['__menu__'] = $this->getMenu();
112+
if ($includeProfiling && Config::getParam('profiling.enable')) {
113+
$vars['__profiling__'] = Inspector::getStats();
114+
}
115+
116+
return $vars;
117+
}
118+
107119
}

src/base/types/CustomApi.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,40 +10,40 @@ abstract class CustomApi extends Api
1010

1111
public function getModelTableMap()
1212
{
13-
return null;
14-
}
15-
16-
public function modelList()
17-
{
18-
return parent::modelList(); // TODO: Change the autogenerated stub
13+
return $this->unsupportedActionResult();
1914
}
2015

2116
public function get($pk)
2217
{
23-
return null;
18+
return $this->unsupportedActionResult();
2419
}
2520

2621
public function delete($pk = null)
2722
{
28-
return null;
23+
return $this->unsupportedActionResult();
2924
}
3025

3126
public function post()
3227
{
33-
return null;
28+
return $this->unsupportedActionResult();
3429
}
3530

3631
public function put($pk)
3732
{
38-
return null;
33+
return $this->unsupportedActionResult();
3934
}
4035

4136
public function admin()
4237
{
43-
return null;
38+
return $this->unsupportedActionResult();
4439
}
4540

4641
public function bulk()
42+
{
43+
return $this->unsupportedActionResult();
44+
}
45+
46+
protected function unsupportedActionResult()
4747
{
4848
return null;
4949
}

src/base/types/CustomAuthApi.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace PSFS\base\types;
44

55
use PSFS\base\exception\ApiException;
6-
use PSFS\base\Security;
6+
use PSFS\base\types\traits\LoggedGuardTrait;
77
use PSFS\base\types\traits\SecureTrait;
88

99
/**
@@ -12,12 +12,16 @@
1212
abstract class CustomAuthApi extends CustomApi
1313
{
1414
use SecureTrait;
15+
use LoggedGuardTrait;
1516

1617
public function init()
1718
{
1819
parent::init();
19-
if (!$this->isLogged()) {
20-
throw new ApiException(t('Resource not authorized'), 401);
21-
}
20+
$this->assertAuthorizedUser();
21+
}
22+
23+
protected function assertAuthorizedUser(): void
24+
{
25+
$this->ensureLoggedOrThrow(new ApiException(t('Resource not authorized'), 401));
2226
}
2327
}

src/base/types/traits/Api/SwaggerDtoComposerTrait.php

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,57 @@ trait SwaggerDtoComposerTrait
1515
*/
1616
protected function checkDtoAttributes(array $dto, array $modelDto, string $dtoName): array
1717
{
18-
foreach ($dto as $param => &$info) {
19-
if (array_key_exists('class', $info)) {
20-
if ($info['is_array']) {
21-
$modelDto['objects'][$dtoName][$param] = [
22-
'type' => 'array',
23-
'items' => [
24-
'$ref' => '#/definitions/' . $info['type'],
25-
]
26-
];
27-
} else {
28-
$modelDto['objects'][$dtoName][$param] = [
29-
'type' => 'object',
30-
'$ref' => '#/definitions/' . $info['type'],
31-
];
32-
}
33-
$modelDto['objects'][$info['class']] = $info['properties'];
34-
$paramDto = $this->checkDtoAttributes($info['properties'], $info['properties'], $info['class']);
35-
if (array_key_exists('objects', $paramDto)) {
36-
$modelDto['objects'] = array_merge($modelDto['objects'], $paramDto['objects']);
37-
}
38-
} else {
18+
$modelDto['objects'] = $modelDto['objects'] ?? [];
19+
$modelDto['objects'][$dtoName] = $modelDto['objects'][$dtoName] ?? [];
20+
21+
foreach ($dto as $param => $info) {
22+
if (!$this->isDtoReference($info)) {
3923
$modelDto['objects'][$dtoName][$param] = $info;
24+
continue;
4025
}
26+
$modelDto['objects'][$dtoName][$param] = $this->buildDtoReferenceSchema($info);
27+
$modelDto = $this->mergeNestedDtoDefinition($modelDto, $info);
4128
}
29+
30+
return $modelDto;
31+
}
32+
33+
private function isDtoReference(mixed $info): bool
34+
{
35+
return is_array($info)
36+
&& array_key_exists('class', $info)
37+
&& array_key_exists('type', $info)
38+
&& array_key_exists('properties', $info);
39+
}
40+
41+
private function buildDtoReferenceSchema(array $info): array
42+
{
43+
if ((bool)($info['is_array'] ?? false)) {
44+
return [
45+
'type' => 'array',
46+
'items' => [
47+
'$ref' => '#/definitions/' . $info['type'],
48+
],
49+
];
50+
}
51+
52+
return [
53+
'type' => 'object',
54+
'$ref' => '#/definitions/' . $info['type'],
55+
];
56+
}
57+
58+
private function mergeNestedDtoDefinition(array $modelDto, array $info): array
59+
{
60+
$className = (string)$info['class'];
61+
$properties = is_array($info['properties']) ? $info['properties'] : [];
62+
$modelDto['objects'][$className] = $properties;
63+
64+
$paramDto = $this->checkDtoAttributes($properties, ['objects' => [$className => $properties]], $className);
65+
if (array_key_exists('objects', $paramDto) && is_array($paramDto['objects'])) {
66+
$modelDto['objects'] = array_merge($modelDto['objects'], $paramDto['objects']);
67+
}
68+
4269
return $modelDto;
4370
}
4471
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace PSFS\base\types\traits;
4+
5+
trait LoggedGuardTrait
6+
{
7+
protected function ensureLoggedOrThrow(\Throwable $exception): void
8+
{
9+
if (!$this->isLogged()) {
10+
throw $exception;
11+
}
12+
}
13+
}

src/base/types/traits/RouteCheckTrait.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ trait RouteCheckTrait
77
/**
88
* @var array
99
*/
10-
private static $route;
10+
private static array $route = [];
1111

1212
public static function getCheckedRoute(): array
1313
{
@@ -16,6 +16,17 @@ public static function getCheckedRoute(): array
1616

1717
public static function setCheckedRoute($route): void
1818
{
19-
self::$route = $route;
19+
self::$route = self::normalizeCheckedRoute($route);
2020
}
21-
}
21+
22+
private static function normalizeCheckedRoute(mixed $route): array
23+
{
24+
if (is_array($route)) {
25+
return $route;
26+
}
27+
if (null === $route || $route === '') {
28+
return [];
29+
}
30+
return [$route];
31+
}
32+
}

tests/base/LoggerExceptionTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace PSFS\tests\base;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use PSFS\base\exception\LoggerException;
7+
8+
class LoggerExceptionTest extends TestCase
9+
{
10+
public function testGetErrorWrapsMessageInHtmlContainer(): void
11+
{
12+
$exception = new LoggerException('boom');
13+
$html = $exception->getError();
14+
15+
$this->assertStringContainsString('boom', $html);
16+
$this->assertStringContainsString('<p style=', $html);
17+
$this->assertStringContainsString('</p>', $html);
18+
}
19+
}

0 commit comments

Comments
 (0)