Dev
Development
Metaport is built with PHP using Silverstripe Framework and is designed and built to run with Docker.
Contributing
First up, have a squiz at how to contribute.
We make heavy use of Continous Integration (CI). Our workflow looks something like this (but it does change sometimes!):
- Push When a branch is pushed, some basic linting tasks are run. They can also be run locally, which increases the chance of these passing first time. Look in
.ci/jobs/lint
. - Merge Request When a merge request is received, almost everything is run: Lint, Test and Deploy (Don't worry about "deploy", this just refers to auto-generated and deployed docs).
- Tag When a new GIT tag is received, the
audit
job is run, a new image is produced and pushed to our Docker Hub, with an accompanying release created in Gitlab.
Requirements
- A recent version of Docker which comes with the
compose
command e.g. >=v19.03.0
. - If making CSS changes to the "metaport-ui" meta-theme: npm >=
v18
.
Procedure
- Clone the contents of the repository:
git clone https://gitlab.com/dcentrica/metaport/metaport-server.git && cd metaport-server
- Configure a local
.env
file. You can review the contents of.env.example
then rename it to.env
to suit your own setup. - Configure your workstation/laptop/PC to listen for requests to
metaport.dev
by modifying your system'shosts
file:
127.0.0.1 metaport.dev
- Bring up all the Docker services with
docker compose
:
docker compose -f docker-compose-dev.yml up -d --build
- (Optional) If you need the included SSO services (OpenLDAP and Keycloak), then use this command instead:
docker compose -f docker-compose-dev.yml -f docker-compose-idp.yml up -d --build
- Import all the component end-of-life data:
docker compose -f docker-compose-dev.yml exec app ./vendor/bin/sake dev/tasks/componentimport
- Create the master encryption key:
docker compose -f docker-compose-dev.yml exec app bash -c 'chmod +x ./bin/setup.sh && ./bin/setupy.sh'
- Optionally run the entire unit test suite:
Grant privileges over the test database:
sudo docker compose -f docker-compose-dev.yml exec db mysql -uroot -padmin mysql -e "GRANT ALL ON \`ss\_tmpdb\_%\`.* TO \`runner\`@\`%\` IDENTIFIED BY 'metaport'"
Execute the test suite:
docker compose -f docker-compose-dev.yml exec app ./vendor/bin/phpunit
- Point your browser at
https://metaport.dev
. (You can safely ignore unsigned certificate warnings from your browser). - Now follow the Quickstart Guide.
- Later, run the following to connect to your team's mailbox (for apps reporting-in using
Email
transport).
docker compose -f docker-compose-dev.yml exec app ./vendor/bin/sake dev/tasks/mailboxfetch
- If making CSS changes, the build command is:
cd metaport-ui/client/src && nvm use && npm i && vite build
Sending Data
Install one of the available agents into your app, and follow the instructions. For evaluation purposes, there's a basic Laravel app found on our Gitlab which you can test with.
Extending
Metaport is built with the Silverstripe Framework for PHP which has its own module ecosystem. If you're familliar with Silverstripe, then ensure you follow the same design patterns.
Adding New Schedules
Adding new Policy
schedules is easy: Copy+Paste an existing one and modify its getSchedule()
and readable_schedule()
methods as applicable. Use CronMaker for a GUI-based cron syntax generator.
Add new EOL Backend
By default, Metaport uses the API provided by endoflife.date, but alternative backends can be used instead. The following instructions are relevant to Metaport CE in self-managed setups.
Warning
It is not recommended to mix data from multiple backends. Doing so will likely cause confusion at best, and data-corruption at the worst.
- Create a new directory under
plugins
. - Write a new PHP class e.g.
MyMetaportEOLBackend.php
which implements BackendProvider. - Ensure the environment variable
MP_COMPONENT_MANAGER
is set correctly e.g.MP_COMPONENT_MANAGER=MyMetaportEOLBackend
- Refresh Metaport's knowledge of the new class:
./vendor/bin/sake dev/build flush=1
- Manually run the import task:
./vendor/bin/sake dev/tasks/componentimport
(This should already be setup to run automatically via cron)
Add new Dependency Manager Backend
When the MP_DM_BACKEND
environment variable is set, Metaport uses the "Classic" dependency and security vulnerability backend. However, it can also talk to the API exposed to it from a local instance of DependencyTrack, and alternative backends can be used as well - though they'll need to be built.
Note
It is OK to run a different Dependency Manager after a previous one, but the connection details will obviously need to be updated.
- Create a new directory under
plugins
. - Write a new PHP class e.g.
MyMetaportDependencyBackend.php
which implements BackendProvider. - Ensure the environment variable
MP_COMPONENT_MANAGER
is set correctly e.g.MP_DEPMANAGER=MyMetaportDependencyBackend
- Refresh Metaport's knowledge of the new class:
./vendor/bin/sake dev/build flush=1
- Login to Metaport as an admin user, and add the connection details to the relevant team UI (If you're running with multiple teams, this process will need to be repeated for each).
SSO
This project comes with docker compose service config for OpenDLAP and phpLDAPadmin in order to work with the Keycloak IDP. These are only required if you're developing with SSO in mind or doing anything with Keycloak.
To build the necessary services, ensure .env
is populated as appropriate (see .env.example
) and then run the following, otherwise, Metaport will work fine without SSO using its own authentication system:
docker compose -f docker-compose.yml -f docker-compose-idp.yml up -d
phpLDAPadmin
phpLDAPadmin is just used as a frontend GUI to OpenLDAP which doesn't have its own UI. If you've built your environment with the SSO services, then you should be able to navigate to http://localhost:8082
and login with the following credentials:
- Username:
cn=admin,dc=my-company,dc=com
- Password:
admin
This project comes with a basic hydration export: .dev/config/phpldapadmin-export.ldif
. Select the "Import" icon on the top-left and follow the instructions (and ignore the errors).
Keycloak
Review the KEYCLOAK_XX
environment variables as documented in .env.example
and transpose into your own .env
file or wherever you manage your environment variables.
Note
Using the docker compose service name keycloak
as the value for the KEYCLOAK_URL
environment variable won't work for curl. Similarly, we cannot use localhost
as that's meaningless in a Docker context. What we need to do is to use the IP assigned to your PC/Laptop/Workstation which has the same effect.
Tip
Use this command to get the appropriate IP (assumes basic home router using DHCP) and set that to the value of the KEYCLOAK_URL
environment variable:
ifconfig | grep 192 | awk '{print $2}'
192.168.20.71
To configure Keycloak itself, visit http://localhost:18080/admin
and login with the following credentials:
- Username:
admin
- Password:
admin
Tip
To quickly hydrate the LDAP server, import the provided LDIF export: .dev/config/phpldapadmin-export.ldif
.
Tip
To setup a Keycloak client quickly, use the provided export: .dev/config/keycloak-client-export.json
. (You'll still need to manually setup an LDAP provider using the guide below).
Tip
Review the comments in app/_config/sso.yml
to guide your Keycloak setup.
Connection and authentication settings
Keycloak > User federation > Add Ldap Providers
UI display name: OpenLDAP (Or whatever you like)
Vendor: Other
Connection URL: ldap://ldap-host (Dev only, substitute for your **actual** LDAP host)
Bind type: Simple
Bind DN: cn=admin,dc=my-company,dc=com (Dev only, substitute for your **actual** LDAP bind DN)
Bind credentials: admin (Dev only, substitute for your **actual** LDAP bind password)
LDAP searching and updating
Edit mode: WRITEABLE
Users DN: ou=People,dc=my-company,dc=com (Dev only, substitute for your **actual** LDAP users DN)
Leave everything else as per the defaults.
Dependency Managers
Metaport is capable of supporting multiple Dependency Manager backends. Out of the box there's support for the following backends:
Classic
Classic simply uses the default facilities of the agent's dependency manager e.g. for Composer we invoke the audit
and show
sub-commands and send that data over the wire to Metaport.
Classic mode will only report dependency and security vulnerability information about application/framework dependencies, and not the O/S or language runtime. If your organisation has access to standalone dependency management software such as Dependency Track, then that will provide everything.
To engage classic mode, both the server and agent need to be told using the MP_DEPMANAGER=Classic
environment variable and --classic=1
parameter respectively. See the agent docs
for more detailed information.
The Dependency Track backend requires the use of docker-copose-dt.yml
.
Self-Signed Certificates
At time of writing, Dependency Track's Docker setup does not run with an HTTPS-enabled configuration. The following command is used to generate a self-signed certificate. Once complete, run docker-compose -f docker-compose-dt.yml up -d
to bring it up, add 127.0.0.1
to /etc/hosts
and then visit: https://dependencytrack.dev:8443/ in a browser.
mkdir -p .dev/services/dt &&
openssl req \
-subj "/C=GB/CN=dependencytrack.dev" \
-addext "subjectAltName = DNS:dependencytrack.dev" \
-x509 \
-nodes \
-days 365 \
-newkey rsa:2048 \
-keyout .dev/services/dt/self-signed.key \
-out .dev/services/dt/self-signed.crt
Using Dependency Track
- Get info about a project:
curl -k "https://dependencytrack.dev:8443/api/v1/bom/cyclonedx/project/$DT_PROJECT_UUID" -H 'Content-Type: application/json' -H "X-API-Key: $DT_TEAM_API_KEY"
- Generate an SBOM (PHP via Composer)
composer CycloneDX:make-sbom --output-format=JSON --output-file="sbom-composer.json"
- Encode
echo "{\"project\": \"$DT_PROJECT_UUID\",\"bom\": \"$( cat ./sbom-composer.json | base64 -w 0 - )\"}" > sbom-composer.encoded.json
- Submit
curl -k --fail -X "PUT" "https://dependencytrack.dev:8443/api/v1/bom" -H 'Content-Type: application/json' -H "X-API-Key: $DT_TEAM_API_KEY" -d @sbom-composer.encoded.json
Configure Metaport
- Navigate to your team's "settings" tab
- Expand the "Dependency Manager Settings" control (If you don't see this, refer to the troubleshooting guide
- The Host field is the name of the Docker service & port e.g.
http://dtrack-apiserver:8080
- The API Token field is the value of the team API token which Dependency Track generates for you when creating a team
- The Team Identifier is the UUID of your team in Dependency Track (it can be found using a call to the
/v1/api/team
endpoint) - Navigate to the desired Metaport application and in its "settings" tab add the Dependency Track project UUID to the Dependency Manager Project ID field. The project UUID can be found from Dependency Track's UI.
Logging
Limited error context is available in the system log /var/log/metaport.log
.