Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
757e553
make prod: Add test users and groups
ata-no-one Nov 17, 2025
cba59c3
lib/Settings: extract operator settings
ata-no-one Nov 17, 2025
b4d91a4
Templates + js
ata-no-one Nov 18, 2025
1b51256
routes + Controller
ata-no-one Nov 18, 2025
a6e643f
Fix controller?
ata-no-one Nov 18, 2025
87d9267
Pack operator-settings, cleanup admin.js
ata-no-one Nov 18, 2025
a131c7e
Prettier, remove TODO, fix message element id
pstadermann Nov 19, 2025
c47c5a9
Last second changes
pstadermann Nov 19, 2025
7ff2a55
WIP
pstadermann Nov 20, 2025
5bd095f
Make tests runnable
ata-no-one Nov 21, 2025
e125b35
SettingsControllerTest
ata-no-one Nov 21, 2025
5df48b0
No async
ata-no-one Nov 21, 2025
d06c15d
unset, removeHeader
ata-no-one Nov 21, 2025
e5a7155
set OCS-APIRequest
GermanCoding Nov 21, 2025
7445eda
More phpunit stuff
Nov 24, 2025
4ed5cc3
apply comments
ata-no-one Nov 24, 2025
0dceff7
Review changes
pstadermann Nov 25, 2025
c0bfe4b
php-cs
Nov 25, 2025
d59aaf1
php-cs
Nov 25, 2025
e18109a
SPDX
Nov 25, 2025
329b7a2
Lines < 120 chars
pstadermann Nov 25, 2025
d37e005
Lines < 120 chars
pstadermann Nov 25, 2025
75103b5
Remove testPostRoutesReturn400ForEmptyBody
ata-no-one Nov 25, 2025
3f8a165
Exclude BaseIntegrationTest from tests
pstadermann Nov 25, 2025
f2e0784
Update copyright
pstadermann Nov 25, 2025
fa4b8df
apply more comments
ata-no-one Nov 26, 2025
0bc9bff
Remove dead/obsolete code
pstadermann Nov 26, 2025
aaee78d
Run all integration tests
pstadermann Nov 26, 2025
3055527
php-cs-fixer
ata-no-one Nov 26, 2025
ec86529
Find .env file properly
ata-no-one Nov 26, 2025
bd43233
php-cs-fixer
ata-no-one Nov 26, 2025
3d18f8a
npm install
ata-no-one Nov 26, 2025
bcb7a13
Test timeout, indentation
ata-no-one Nov 26, 2025
8402fd3
Update packages
ata-no-one Nov 26, 2025
808534d
Simplify lint-eslint
pstadermann Nov 26, 2025
cb1bd19
Newline
pstadermann Nov 26, 2025
89df543
fix test
ata-no-one Nov 26, 2025
051a4fe
add github hostname env
ata-no-one Nov 26, 2025
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
20 changes: 1 addition & 19 deletions .github/workflows/lint-eslint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ on: pull_request
permissions:
contents: read


jobs:
changes:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -43,14 +42,12 @@ jobs:
- '**.ts'
- '**.vue'

lint:
eslint:
runs-on: ubuntu-latest

needs: changes
if: needs.changes.outputs.src != 'false'

name: NPM lint

steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
Expand Down Expand Up @@ -80,18 +77,3 @@ jobs:

- name: Lint
run: npm run lint

summary:
permissions:
contents: none
runs-on: ubuntu-latest
needs: [changes, lint]

if: always()

# This is the summary, we just avoid to rename it so that branch protection rules still match
name: eslint

steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.lint.result != 'success' }}; then exit 1; fi
23 changes: 8 additions & 15 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ defaults:
shell: bash
on:
push:
branches: ["main"]
tags: ["*"]
branches: ['main']
tags: ['*']
pull_request:
workflow_dispatch:

Expand Down Expand Up @@ -39,15 +39,15 @@ jobs:
env:
IS_CI: 1
options: --name nextcloud-antivirus-build-container
needs:
needs:
- build-devcontainer
steps:
- uses: actions/checkout@v4

- name: postCreateCommands
run: |
source .devcontainer/postCreateCommands.sh

- name: add composer bin to path
run: |
echo $(composer config home --global)/vendor/bin >> $GITHUB_PATH
Expand Down Expand Up @@ -82,21 +82,14 @@ jobs:
run: |
docker network connect nextcloud-gdata-antivirus_nextcloud-network nextcloud-antivirus-build-container

- name: run tests
id: bats-tests
- name: run integration tests
env:
CLIENT_ID: ${{ secrets.VAAS_CLIENT_ID }}
CLIENT_SECRET: ${{ secrets.VAAS_CLIENT_SECRET }}
NEXTCLOUD_HOSTNAME: nextcloud-container
run: |
if bats --verbose-run --timing --trace ./tests/bats; then
echo "bats_run=success" | tee -a "$GITHUB_OUTPUT";
else
echo "bats_run=fail" | tee -a "$GITHUB_OUTPUT";
fi

- name: fail if bats tests did fail
if: steps.bats-tests.outputs.bats_run == 'fail'
run: exit 1
bats --verbose-run --timing --trace ./tests/bats
./vendor/bin/phpunit --bootstrap tests/integration/bootstrap.php tests/integration/

- uses: actions/upload-artifact@master
with:
Expand Down
5 changes: 5 additions & 0 deletions .prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-FileCopyrightText: 2025 G DATA CyberDefense AG <vaas@gdata.de>
# SPDX-License-Identifier: AGPL-3.0-or-later

semi: false
singleQuote: true
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ unittests:
composer install
./vendor/bin/phpunit --bootstrap tests/unittests/bootstrap.php tests/unittests/ --testdox

# Run integration tests
.PHONY: integrationtests
integrationtests:
./scripts/run-app.sh "32.0.0" 1
composer install
./vendor/bin/phpunit -c tests/integration/phpunit.xml tests/integration/ --testdox

# Run bats tests
.PHONY: bats
bats:
Expand Down
1 change: 1 addition & 0 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Please make sure the "Authentication Method" "Resource Owner Password Flow" is s
</commands>
<settings>
<admin>OCA\GDataVaas\Settings\VaasAdmin</admin>
<admin>OCA\GDataVaas\Settings\VaasOperator</admin>
<admin-section>OCA\GDataVaas\Settings\VaasAdminSection</admin-section>
</settings>
<activity>
Expand Down
18 changes: 11 additions & 7 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,26 @@
return [
'resources' => [],
'routes' => [
// user
['name' => 'scan#scan', 'url' => '/scan', 'verb' => 'POST'],
['name' => 'settings#setconfig', 'url' => '/setconfig', 'verb' => 'POST'],
['name' => 'settings#setadvancedconfig', 'url' => '/setadvancedconfig', 'verb' => 'POST'],
// operator
['name' => 'settings#setOperatorSettings', 'url' => '/operatorSettings', 'verb' => 'POST'],
['name' => 'settings#getSendMailOnVirusUpload', 'url' => '/getSendMailOnVirusUpload', 'verb' => 'GET'],
['name' => 'settings#setSendMailOnVirusUpload', 'url' => '/setSendMailOnVirusUpload', 'verb' => 'POST'],
['name' => 'settings#setAutoScan', 'url' => '/setAutoScan', 'verb' => 'POST'],
['name' => 'settings#getAutoScan', 'url' => '/getAutoScan', 'verb' => 'GET'],
['name' => 'settings#setPrefixMalicious', 'url' => '/setPrefixMalicious', 'verb' => 'POST'],
['name' => 'settings#getPrefixMalicious', 'url' => '/getPrefixMalicious', 'verb' => 'GET'],
['name' => 'settings#getAuthMethod', 'url' => '/getAuthMethod', 'verb' => 'GET'],
['name' => 'settings#setDisableUnscannedTag', 'url' => '/setDisableUnscannedTag', 'verb' => 'POST'],
['name' => 'settings#getDisableUnscannedTag', 'url' => '/getDisableUnscannedTag', 'verb' => 'GET'],
['name' => 'settings#resetAllTags', 'url' => '/resetalltags', 'verb' => 'POST'],
['name' => 'settings#getCounters', 'url' => '/getCounters', 'verb' => 'GET'],
['name' => 'settings#getSendMailOnVirusUpload', 'url' => '/getSendMailOnVirusUpload', 'verb' => 'GET'],
['name' => 'settings#setSendMailOnVirusUpload', 'url' => '/setSendMailOnVirusUpload', 'verb' => 'POST'],
// admin
['name' => 'settings#setAdminSettings', 'url' => '/adminSettings', 'verb' => 'POST'],
['name' => 'settings#setAdvancedConfig', 'url' => '/setAdvancedConfig', 'verb' => 'POST'],
['name' => 'settings#getAuthMethod', 'url' => '/getAuthMethod', 'verb' => 'GET'],
['name' => 'settings#resetAllTags', 'url' => '/resetalltags', 'verb' => 'POST'],
['name' => 'settings#testsettings', 'url' => '/testsettings', 'verb' => 'POST'],
['name' => 'settings#getCache', 'url' => '/getCache', 'verb' => 'GET'],
['name' => 'settings#getHashlookup', 'url' => '/getHashlookup', 'verb' => 'GET']
['name' => 'settings#getHashlookup', 'url' => '/getHashlookup', 'verb' => 'GET'],
]
];
11 changes: 7 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
"coduo/php-humanizer": "5.0.0"
},
"require-dev": {
"nextcloud/ocp": "v32.0.0",
"nextcloud/ocp": "v32.0.2",
"psalm/phar": "6.8.2",
"nextcloud/coding-standard": "v1.4.0",
"colinodell/psr-testlogger": "1.3.0",
"phpunit/phpunit": "10.5.52",
"symfony/console": "v6.4.24"
"colinodell/psr-testlogger": "1.3.1",
"phpunit/phpunit": "10.5.58",
"symfony/console": "v6.4.27",
"amphp/http-client": "5.3.4",
"amphp/amp": "3.1.1",
"vlucas/phpdotenv": "5.6.2"
},
"autoload": {
"psr-4": {
Expand Down
53 changes: 35 additions & 18 deletions lib/Controller/SettingsController.php
Comment thread
pstadermann marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

use OCA\GDataVaas\Service\TagService;
use OCA\GDataVaas\Service\VerdictService;
use OCA\GDataVaas\Settings\VaasOperator;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\JSONResponse;
use OCP\DB\Exception;
use OCP\IAppConfig;
Expand Down Expand Up @@ -40,29 +42,17 @@ public function __construct(
$this->verdictService = $verdictService;
}

public function setconfig(
public function setAdminSettings(
$username,
$password,
$clientId,
$clientSecret,
$authMethod,
$quarantineFolder,
$scanOnlyThis,
$doNotScanThis,
$notifyMails,
$maxScanSize,
$timeout,
bool $cache,
bool $hashlookup,
): JSONResponse {
if (!empty($notifyMails)) {
$mails = explode(',', preg_replace('/\s+/', '', $notifyMails));
foreach ($mails as $mail) {
if ($this->mailer->validateMailAddress($mail) === false) {
return new JSONResponse(['status' => 'error', 'message' => 'Invalid email address: ' . $mail]);
}
}
}
if ((int)$maxScanSize < 1) {
return new JSONResponse(['status' => 'error', 'message' => 'Invalid max scan size: ' . $maxScanSize]);
}
Expand All @@ -74,37 +64,59 @@ public function setconfig(
$this->config->setValueString($this->appName, 'clientId', $clientId);
$this->config->setValueString($this->appName, 'clientSecret', $clientSecret);
$this->config->setValueString($this->appName, 'authMethod', $authMethod);
$this->config->setValueString($this->appName, 'quarantineFolder', $quarantineFolder);
$this->config->setValueString($this->appName, 'scanOnlyThis', $scanOnlyThis);
$this->config->setValueString($this->appName, 'doNotScanThis', $doNotScanThis);
$this->config->setValueString($this->appName, 'notifyMails', $notifyMails);
$this->config->setValueInt($this->appName, 'maxScanSizeInMB', (int)$maxScanSize);
$this->config->setValueInt($this->appName, 'timeout', (int)$timeout);
$this->config->setValueBool($this->appName, 'cache', $cache);
$this->config->setValueBool($this->appName, 'hashlookup', $hashlookup);
return new JSONResponse(['status' => 'success']);
}

public function setadvancedconfig($tokenEndpoint, $vaasUrl): JSONResponse {
public function setAdvancedConfig($tokenEndpoint, $vaasUrl): JSONResponse {
$this->config->setValueString($this->appName, 'tokenEndpoint', $tokenEndpoint);
$this->config->setValueString($this->appName, 'vaasUrl', $vaasUrl);
return new JSONResponse(['status' => 'success']);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function setOperatorSettings(
$quarantineFolder,
$scanOnlyThis,
$doNotScanThis,
$notifyMails,
): JSONResponse {
if (!empty($notifyMails)) {
$mails = explode(',', preg_replace('/\s+/', '', $notifyMails));
foreach ($mails as $mail) {
if ($this->mailer->validateMailAddress($mail) === false) {
return new JSONResponse(['status' => 'error', 'message' => 'Invalid email address: ' . $mail]);
}
}
}
$this->config->setValueString($this->appName, 'quarantineFolder', $quarantineFolder);
$this->config->setValueString($this->appName, 'scanOnlyThis', $scanOnlyThis);
$this->config->setValueString($this->appName, 'doNotScanThis', $doNotScanThis);
$this->config->setValueString($this->appName, 'notifyMails', $notifyMails);
return new JSONResponse(['status' => 'success']);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function setAutoScan(bool $autoScanFiles): JSONResponse {
$this->config->setValueBool($this->appName, 'autoScanFiles', $autoScanFiles);
return new JSONResponse(['status' => 'success']);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function getAutoScan(): JSONResponse {
return new JSONResponse(['status' => $this->config->getValueBool($this->appName, 'autoScanFiles')]);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function setPrefixMalicious(bool $prefixMalicious): JSONResponse {
$this->config->setValueBool($this->appName, 'prefixMalicious', $prefixMalicious);
return new JSONResponse(['status' => 'success']);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function getPrefixMalicious(): JSONResponse {
return new JSONResponse(['status' => $this->config->getValueBool($this->appName, 'prefixMalicious')]);
}
Expand All @@ -113,11 +125,13 @@ public function getAuthMethod(): JSONResponse {
return new JSONResponse(['status' => $this->config->getValueString($this->appName, 'authMethod')]);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function setDisableUnscannedTag(bool $disableUnscannedTag): JSONResponse {
$this->config->setValueBool($this->appName, 'disableUnscannedTag', $disableUnscannedTag);
return new JSONResponse(['status' => 'success']);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function getDisableUnscannedTag(): JSONResponse {
return new JSONResponse(['status' => $this->config->getValueBool($this->appName, 'disableUnscannedTag')]);
}
Expand All @@ -127,6 +141,7 @@ public function resetAllTags(): JSONResponse {
return new JSONResponse(['status' => 'success']);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function getCounters(): JSONResponse {
try {
$filesCount = $this->tagService->getScannedFilesCount();
Expand All @@ -143,12 +158,14 @@ public function getCounters(): JSONResponse {
]);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function getSendMailOnVirusUpload(): JSONResponse {
return new JSONResponse(
['status' => $this->config->getValueBool($this->appName, 'sendMailOnVirusUpload')]
);
}

#[AuthorizedAdminSetting(settings: VaasOperator::class)]
public function setSendMailOnVirusUpload(bool $sendMailOnVirusUpload): JSONResponse {
$this->config->setValueBool($this->appName, 'sendMailOnVirusUpload', $sendMailOnVirusUpload);
return new JSONResponse(['status' => 'success']);
Expand Down
11 changes: 0 additions & 11 deletions lib/Settings/VaasAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,6 @@ public function getForm(): TemplateResponse {
'vaasUrl',
'https://gateway.staging.vaas.gdatasecurity.de'
),
'quarantineFolder'
=> $this->config->getValueString(Application::APP_ID, 'quarantineFolder', 'Quarantine'),
'autoScanFiles' => $this->config->getValueBool(Application::APP_ID, 'autoScanFiles'),
'prefixMalicious'
=> $this->config->getValueBool(Application::APP_ID, 'prefixMalicious', true),
'disableUnscannedTag' => $this->config->getValueBool(Application::APP_ID, 'disableUnscannedTag'),
'scanOnlyThis' => $this->config->getValueString(Application::APP_ID, 'scanOnlyThis'),
'doNotScanThis' => $this->config->getValueString(Application::APP_ID, 'doNotScanThis'),
'notifyMail' => $this->config->getValueString(Application::APP_ID, 'notifyMails'),
'sendMailOnVirusUpload'
=> $this->config->getValueBool(Application::APP_ID, 'sendMailOnVirusUpload'),
'maxScanSizeInMB'
=> $this->config->getValueInt(Application::APP_ID, 'maxScanSizeInMB', 256),
'timeout' => $this->config->getValueInt(Application::APP_ID, 'timeout', 300),
Expand Down
Loading
Loading