Skip to content

Commit

Permalink
removed "optional API Scope" support (#220)
Browse files Browse the repository at this point in the history
* added URL encoding for Docker Container Pull action
* added two logs with `info` level for PullImage action
* removed "optional API Scope" support
* added AppAPI options toggles in Admin settings
* added RestartPolicy option to created containers

CI fails unrelated:
pytest-dev/pytest-asyncio#737

---------

Signed-off-by: Alexander Piskun <bigcat88@icloud.com>
Signed-off-by: Andrey Borysenko <andrey18106x@gmail.com>
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
Co-authored-by: Andrey Borysenko <andrey18106x@gmail.com>
Co-authored-by: Nextcloud bot <bot@nextcloud.com>
Co-authored-by: rakekniven <2069590+rakekniven@users.noreply.github.com>
  • Loading branch information
4 people authored Feb 1, 2024
1 parent 1568a92 commit 7ad5541
Show file tree
Hide file tree
Showing 22 changed files with 488 additions and 252 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/tests-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ jobs:
docker network create master_bridge
docker run -v /var/run/docker.sock:/var/run/docker.sock \
-e NC_HAPROXY_PASSWORD="some_secure_password" \
--net master_bridge --name aa-docker-socket-proxy -h aa-docker-socket-proxy \
--privileged -d ghcr.io/cloud-py-api/aa-docker-socket-proxy:latest
--net master_bridge --name nextcloud-appapi-dsp -h nextcloud-appapi-dsp \
--privileged -d ghcr.io/cloud-py-api/nextcloud-appapi-dsp:latest
docker run --net master_bridge --name nextcloud --rm -d ${{ env.docker-image }}
sleep 60s
Expand All @@ -249,7 +249,7 @@ jobs:
docker exec -w /var/www/html/apps/${{ env.APP_NAME }} nextcloud git checkout FETCH_HEAD
docker exec nextcloud sudo -u www-data php occ app:enable app_api
docker exec nextcloud sudo -u www-data php occ app_api:daemon:register \
docker_by_port Docker docker-install http aa-docker-socket-proxy:2375 http://nextcloud/index.php \
docker_by_port Docker docker-install http nextcloud-appapi-dsp:2375 http://nextcloud/index.php \
--net=master_bridge --haproxy_password=some_secure_password
docker exec nextcloud sudo -u www-data php occ app_api:daemon:list
docker exec nextcloud sudo -u www-data php occ app_api:app:deploy skeleton docker_by_port \
Expand Down Expand Up @@ -326,12 +326,12 @@ jobs:
-e NC_HAPROXY_PASSWORD="some_secure_password" \
-e BIND_ADDRESS="172.17.0.1" \
-e EX_APPS_NET_FOR_HTTPS="ipv4@localhost" \
--net host --name aa-docker-socket-proxy -h aa-docker-socket-proxy \
--privileged -d ghcr.io/cloud-py-api/aa-docker-socket-proxy:latest
--net host --name nextcloud-appapi-dsp -h nextcloud-appapi-dsp \
--privileged -d ghcr.io/cloud-py-api/nextcloud-appapi-dsp:latest
docker run --net=bridge --name=nextcloud -p 8080:80 --rm -d ${{ env.docker-image }}
sleep 60s
hostname -I
docker exec aa-docker-socket-proxy ip addr show | grep inet | awk '{print $2}' | cut -d/ -f1
docker exec nextcloud-appapi-dsp ip addr show | grep inet | awk '{print $2}' | cut -d/ -f1
- name: Install AppAPI
run: |
Expand Down Expand Up @@ -363,7 +363,7 @@ jobs:
- name: Save HaProxy logs
if: always()
run: docker logs aa-docker-socket-proxy > haproxy.log 2>&1
run: docker logs nextcloud-appapi-dsp > haproxy.log 2>&1

- name: Save container info & logs
if: always()
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/tests-special.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ jobs:
sleep 5s
php occ app_api:daemon:register manual_install "Manual Install" manual-install http localhost 0
php occ app_api:app:register $APP_ID manual_install --json-info \
"{\"appid\":\"$APP_ID\",\"name\":\"$APP_ID\",\"daemon_config_name\":\"manual_install\",\"version\":\"$APP_VERSION\",\"secret\":\"$APP_SECRET\",\"port\":$APP_PORT,\"scopes\":{\"required\":[\"SYSTEM\", \"NOTIFICATIONS\"],\"optional\":[\"USER_INFO\"]},\"system_app\":1}" \
"{\"appid\":\"$APP_ID\",\"name\":\"$APP_ID\",\"daemon_config_name\":\"manual_install\",\"version\":\"$APP_VERSION\",\"secret\":\"$APP_SECRET\",\"port\":$APP_PORT,\"scopes\":[\"SYSTEM\", \"NOTIFICATIONS\", \"USER_INFO\"],\"system_app\":1}" \
--force-scopes --wait-finish
kill -15 $(cat /tmp/_install.pid)
timeout 3m tail --pid=$(cat /tmp/_install.pid) -f /dev/null
Expand Down Expand Up @@ -220,7 +220,7 @@ jobs:
sleep 5s
php occ app_api:daemon:register manual_install "Manual Install" manual-install http localhost 0
php occ app_api:app:register $APP_ID manual_install --json-info \
"{\"appid\":\"$APP_ID\",\"name\":\"$APP_ID\",\"daemon_config_name\":\"manual_install\",\"version\":\"$APP_VERSION\",\"secret\":\"$APP_SECRET\",\"port\":$APP_PORT,\"scopes\":{\"required\":[\"ALL\"],\"optional\":[]},\"system_app\":1}" \
"{\"appid\":\"$APP_ID\",\"name\":\"$APP_ID\",\"daemon_config_name\":\"manual_install\",\"version\":\"$APP_VERSION\",\"secret\":\"$APP_SECRET\",\"port\":$APP_PORT,\"scopes\":[\"ALL\"],\"system_app\":1}" \
--force-scopes --wait-finish
kill -15 $(cat /tmp/_install.pid)
timeout 3m tail --pid=$(cat /tmp/_install.pid) -f /dev/null
Expand All @@ -238,7 +238,7 @@ jobs:
echo $! > /tmp/_install.pid
sleep 5s
php occ app_api:app:register $APP_ID manual_install --json-info \
"{\"appid\":\"$APP_ID\",\"name\":\"$APP_ID\",\"daemon_config_name\":\"manual_install\",\"version\":\"$APP_VERSION\",\"secret\":\"$APP_SECRET\",\"port\":$APP_PORT,\"scopes\":{\"required\":[\"SYSTEM\"],\"optional\":[]},\"system_app\":1}" \
"{\"appid\":\"$APP_ID\",\"name\":\"$APP_ID\",\"daemon_config_name\":\"manual_install\",\"version\":\"$APP_VERSION\",\"secret\":\"$APP_SECRET\",\"port\":$APP_PORT,\"scopes\":[\"SYSTEM\"],\"system_app\":1}" \
--force-scopes --wait-finish
kill -15 $(cat /tmp/_install.pid)
timeout 3m tail --pid=$(cat /tmp/_install.pid) -f /dev/null
Expand All @@ -253,7 +253,7 @@ jobs:
echo $! > /tmp/_install.pid
sleep 5s
php occ app_api:app:register $APP_ID manual_install --json-info \
"{\"appid\":\"$APP_ID\",\"name\":\"$APP_ID\",\"daemon_config_name\":\"manual_install\",\"version\":\"$APP_VERSION\",\"secret\":\"$APP_SECRET\",\"port\":$APP_PORT,\"scopes\":{\"required\":[\"ALL\"],\"optional\":[]},\"system_app\":0}" \
"{\"appid\":\"$APP_ID\",\"name\":\"$APP_ID\",\"daemon_config_name\":\"manual_install\",\"version\":\"$APP_VERSION\",\"secret\":\"$APP_SECRET\",\"port\":$APP_PORT,\"scopes\":[\"ALL\"],\"system_app\":0}" \
--force-scopes --wait-finish
kill -15 $(cat /tmp/_install.pid)
timeout 3m tail --pid=$(cat /tmp/_install.pid) -f /dev/null
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

## [2.0.3 - 2024-02-01]

### Added

- Added RestartPolicy option (Admin settings) #220
- Added ExApp init timeout option (Admin settings) #220

### Changed

- Removed support of `Optional` API scopes. #220

## [2.0.2 - 2024-01-28]

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ to join us in shaping a more versatile, stable, and secure app landscape.
*Your insights, suggestions, and contributions are invaluable to us.*
]]></description>
<version>2.0.2</version>
<version>2.0.3</version>
<licence>agpl</licence>
<author mail="andrey18106x@gmail.com" homepage="https://github.com/andrey18106">Andrey Borysenko</author>
<author mail="bigcat88@icloud.com" homepage="https://github.com/bigcat88">Alexander Piskun</author>
Expand Down
4 changes: 1 addition & 3 deletions docs/Concepts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ Concepts
API Access Control Mechanism
----------------------------

Each application defines required and an optional list of API groups it intends to access.

Administrators can permit or deny an application's access to any API from the **optional** list.
Each application defines list of API groups it intends to access.

This system easily allows you to increase the level of trust in applications.
Even prior to installation, it's possible to ascertain the API groups to which an application will gain access.
Expand Down
2 changes: 1 addition & 1 deletion docs/DeployConfigurations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ Suggested way to communicate with Docker: via ``docker-socket-proxy``.
class ExApp3 python

Suggested config values(template *Docker Socket Proxy*):
1. Daemon host: aa-docker-socket-proxy:2375
1. Daemon host: nextcloud-appapi-dsp:2375
2. HTTPS checkbox: ``disabled``
3. Network: `user defined network <https://docs.docker.com/network/#user-defined-networks>`_
4. HaProxy password: ``optional``
Expand Down
72 changes: 9 additions & 63 deletions docs/tech_details/Deployment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,59 +27,24 @@ This can be done by ``occ`` CLI command **app_api:daemon:register**:

.. code-block:: bash
app_api:daemon:register <name> <display-name> <accepts-deploy-id> <protocol> <host> <nextcloud_url> [--net NET] [--host HOST] [--ssl_key SSL_KEY] [--ssl_key_password SSL_KEY_PASSWORD] [--ssl_cert SSL_CERT] [--ssl_cert_password SSL_CERT_PASSWORD] [--]
app_api:daemon:register <name> <display-name> <accepts-deploy-id> <protocol> <host> <nextcloud_url> [--net NET] [--haproxy_password PASSWORD] [--]
Arguments
*********

* ``name`` - unique name of the daemon (e.g. ``docker_local_sock``)
* ``display-name`` - name of the daemon (e.g. ``My Local Docker``, will be displayed in the UI)
* ``accepts-deploy-id`` - type of deployment (``docker-install`` or ``manual-install``)
* ``protocol`` - protocol used to connect to the daemon (``unix-socket``, ``http`` or ``https``)
* ``host`` - host of the daemon (e.g. ``/var/run/docker.sock`` for ``unix-socket`` protocol or ``host:port`` for ``http(s)`` protocol)
* ``protocol`` - protocol used to connect to the daemon (``http`` or ``https``)
* ``host`` - host of the daemon (e.g. ``/var/run/docker.sock`` or ``host:port``)
* ``nextcloud_url`` - Nextcloud URL, Daemon config required option (e.g. ``https://nextcloud.local``)
* ``--gpu`` - ``[optional]`` GPU device to expose to the daemon (e.g. ``/dev/dri``)

Options
*******

* ``--net [network-name]`` - ``[required]`` network name to bind docker container to (default: ``host``)
* ``--hostname HOST`` - ``[required]`` host to expose daemon to (defaults to ExApp appid)
* ``--ssl_key SSL_KEY`` - ``[optional]`` path to SSL key file (local absolute path)
* ``--ssl_password SSL_PASSWORD`` - ``[optional]`` SSL key password
* ``--ssl_cert SSL_CERT`` - ``[optional]`` path to SSL cert file (local absolute path)
* ``--ssl_cert_password SSL_CERT_PASSWORD`` - ``[optional]`` SSL cert password

DeployConfig
************

DeployConfig is a set of additional options in Daemon config, which are used in deployment algorithms to configure
ExApp container.

.. code-block:: json
{
"net": "nextcloud",
"host": null,
"nextcloud_url": "https://nextcloud.local",
"ssl_key": "/path/to/ssl/key.pem",
"ssl_key_password": "ssl_key_password",
"ssl_cert": "/path/to/ssl/cert.pem",
"ssl_cert_password": "ssl_cert_password",
"gpus": ["/dev/dri"],
}
DeployConfig options
""""""""""""""""""""

* ``net`` **[required]** - network name to bind docker container to (default: ``host``)
* ``host`` *[optional]* - in case Docker is on remote host, this should be a hostname of remote machine
* ``nextcloud_url`` **[required]** - Nextcloud URL (e.g. ``https://nextcloud.local``)
* ``ssl_key`` *[optional]* - path to SSL key file (local absolute path)
* ``ssl_key_password`` *[optional]* - SSL key password
* ``ssl_cert`` *[optional]* - path to SSL cert file (local absolute path)
* ``ssl_cert_password`` *[optional]* - SSL cert password
* ``--haproxy_password PASSWORD`` - ``[optional]`` password if ``AppAPI Docker Socket Proxy`` is used
* ``--gpu`` - ``[optional]`` GPU device to expose to the daemon (e.g. ``/dev/dri``)

.. note::
Common configurations are tested by CI in our repository, see `workflows on github <https://github.com/cloud-py-api/app_api/blob/main/.github/workflows/tests-deploy.yml>`_.
Expand All @@ -91,7 +56,7 @@ Example of ``occ`` **app_api:daemon:register** command:

.. code-block:: bash
sudo -u www-data php occ app_api:daemon:register docker_local_sock "My Local Docker" docker-install unix-socket /var/run/docker.sock "https://nextcloud.local" --net nextcloud
sudo -u www-data php occ app_api:daemon:register docker_local_sock "My Local Docker" docker-install http /var/run/docker.sock "https://nextcloud.local" --net nextcloud
ExApp deployment
Expand Down Expand Up @@ -156,7 +121,7 @@ For all examples and applications we release we usually add manual_install comma
.. code-block::
php occ app_api:app:register nc_py_api manual_install --json-info \
"{\"appid\":\"nc_py_api\",\"name\":\"nc_py_api\",\"daemon_config_name\":\"manual_install\",\"version\":\"1.0.0\",\"secret\":\"12345\",\"host\":\"localhost\",\"port\":$APP_PORT,\"scopes\":{\"required\":[\"SYSTEM\", \"FILES\", \"FILES_SHARING\"],\"optional\":[\"USER_INFO\", \"USER_STATUS\", \"NOTIFICATIONS\", \"WEATHER_STATUS\", \"TALK\"]},\"protocol\":\"http\",\"system_app\":1}" \
"{\"appid\":\"nc_py_api\",\"name\":\"nc_py_api\",\"daemon_config_name\":\"manual_install\",\"version\":\"1.0.0\",\"secret\":\"12345\",\"port\":$APP_PORT,\"scopes\":[\"SYSTEM\", \"FILES\", \"FILES_SHARING\", \"USER_INFO\", \"USER_STATUS\", \"NOTIFICATIONS\", \"WEATHER_STATUS\", \"TALK\"],\"system_app\":1}" \
--force-scopes
.. note:: **Deployment/Startup of App should be done by developer when manual_install DeployConfig type is used.**
Expand All @@ -172,7 +137,6 @@ The following env variables are required and built automatically:
* ``APP_ID`` - ExApp appid
* ``APP_DISPLAY_NAME`` - ExApp display name
* ``APP_VERSION`` - ExApp version
* ``APP_PROTOCOL`` - protocol ExApp is listening on (http|https)
* ``APP_HOST`` - host ExApp is listening on
* ``APP_PORT`` - port ExApp is listening on (randomly selected by AppAPI)
* ``APP_PERSISTENT_STORAGE`` - path to mounted volume for persistent data storage between ExApp updates
Expand All @@ -182,19 +146,6 @@ The following env variables are required and built automatically:
.. note::
Additional envs can be passed using multiple ``--env ENV_NAME=ENV_VAL`` options

Docker daemon remote
********************

If you want to connect to remote docker daemon with TLS enabled, you need to provide SSL key and cert by provided options.
Important: before deploy you need to import ca.pem file using `occ security <https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ_command.html#security>`_ command:

``php occ security:certificates:import /path/to/ca.pem``

The daemon must be configured with ``protocol=http|https``, ``host=https://dockerapihost``, ``port=8443``.
DaemonConfig deploy options ``ssl_key`` and ``ssl_cert`` must be provided with local absolute paths to SSL key and cert files.
In case of password protected key or cert, you can provide ``ssl_key_password`` and ``ssl_cert_password`` options.
More info about how to configure daemon will be added soon.

ExApp registration
------------------

Expand Down Expand Up @@ -250,14 +201,9 @@ It has the same structure as Nextcloud appinfo/info.xml file, but with some addi
<image-tag>latest</image-tag>
</docker-install>
<scopes>
<required>
<value>TALK</value>
<value>TALK_BOT</value>
</required>
<optional>
</optional>
<value>TALK</value>
<value>TALK_BOT</value>
</scopes>
<protocol>http</protocol>
<system>0</system>
</ex-app>
...
4 changes: 2 additions & 2 deletions lib/BackgroundJob/ExAppInitStatusCheckJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public function __construct(
}

protected function run($argument): void {
// Iterate over all ExApp and check for status.init_start_time if it is older than ex_app_init_timeout minutes
// Iterate over all ExApp and check for status.init_start_time if it is older than init_timeout minutes
// set status.progress=0 and status.error message with timeout error
try {
$exApps = $this->mapper->findAll();
$initTimeoutMinutes = intval($this->config->getAppValue(Application::APP_ID, 'ex_app_init_timeout', '40'));
$initTimeoutMinutes = intval($this->config->getAppValue(Application::APP_ID, 'init_timeout', '40'));
foreach ($exApps as $exApp) {
$status = $exApp->getStatus();
if (!isset($status['init_start_time'])) {
Expand Down
24 changes: 2 additions & 22 deletions lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,16 @@
namespace OCA\AppAPI;

use OCA\AppAPI\AppInfo\Application;
use OCA\AppAPI\Db\ExAppScope;
use OCA\AppAPI\Service\ExAppScopesService;
use OCA\AppAPI\Service\ExAppService;
use OCA\AppAPI\Service\ProvidersAI\TextProcessingService;
use OCP\App\IAppManager;
use OCP\Capabilities\ICapability;
use OCP\IConfig;
use OCP\IRequest;

class Capabilities implements ICapability {

public function __construct(
private IConfig $config,
private IAppManager $appManager,
private ExAppService $service,
private ExAppScopesService $exAppScopesService,
private IRequest $request,
private readonly IConfig $config,
private readonly IAppManager $appManager,
) {
}

Expand All @@ -33,21 +26,8 @@ public function getCapabilities(): array {
'task_types' => array_keys(TextProcessingService::TASK_TYPES),
]
];
$this->attachExAppScopes($capabilities);
return [
'app_api' => $capabilities,
];
}

private function attachExAppScopes(&$capabilities): void {
$appId = $this->request->getHeader('EX-APP-ID');
if ($appId !== '') {
$exApp = $this->service->getExApp($appId);
if ($exApp !== null) {
$capabilities['scopes'] = array_map(function (ExAppScope $scope) {
return intval($scope->getScopeGroup());
}, $this->exAppScopesService->getExAppScopes($exApp));
}
}
}
}
2 changes: 1 addition & 1 deletion lib/Command/ExApp/Deploy.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$daemonConfig->getProtocol(),
$daemonConfig->getHost(),
$daemonConfig->getDeployConfig(),
(int)explode('=', $deployParams['container_params']['env'][7])[1],
(int)explode('=', $deployParams['container_params']['env'][6])[1],
$auth,
);
if (!$this->service->heartbeatExApp($exAppUrl, $auth)) {
Expand Down
Loading

0 comments on commit 7ad5541

Please sign in to comment.