89 Commits
Author SHA1 Message Date
lebaudantoineandaleb_the_flash 8c54e701c1 🔧(helm) configure resource server in staging
Allow desk-staging app to interact with AgentConnect integration env
to introspect a received access token.

Other environment (pre-prod and production) will be configured when
at least one interconnection with a service provider has been
validated.
2024-08-30 13:12:25 +02:00
lebaudantoineandaleb_the_flash 9adb2d4cf4 📝(backend) draft a minimal documentation on resource server
I've committed few of my notes for my future myself, helping me to
run locally the stack. These notes are raw, I'll be more than happy
to refine them when I got sufficient time. Please feel free to ping
me if you have any question.
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash bb5058c478 🔊(backend) enable debug logs in development
Enhance developer experience, unmuting some debug information,
that weren't taken into account.
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash 78818ba541 🩹(backend) enable resource server authentication if properly configured
Tests are missing, let's ship it, I'll open an issue.

Without such protection, the whole app would crash if the resource server is
not configured. The fallback backend would return an appropriate error to
the client if the resource server is improperly configured.
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash f1a2b7c603 (backend) authenticate requests using an access token issued by AC
Overload mozilla-django-oidc class to support an authentication method
with the resource server backend.

This enables any route of the API to be called with an access token
issued by Agent Connect.
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash 5634a7f390 (backend) add resource server backend
Why:

Many services in La Suite rely on Agent Connect to authenticate their users.
Delegating  authentication to Agent Connect is highly beneficial. With a central
party (Agent Connect)  handling user authentication, our services can seamlessly
communicate with each other.  Our backend must be able to receive and verify
access tokens issued by Agent Connect.

Additionally, it should ensure that the resource owner has granted permission
for our  data to the service provider transmitting the access token.

How:

Our backend needs to verify access tokens by introspecting them. This involves
requesting the Authorization Server to validate the access token received in
the authentication header. The Authorization Server validates the token's
integrity, provides authentication and authorization information about
the user currently logged into the service provider requesting data from
the resource server.

The data returned by the Authorization Server to the resource server
is encrypted and signed. To encrypt the introspection token, the Authorization
Server retrieves the resource server's public key from
the new ‘/jwks’ endpoint.

Encryption parameters, such as algorithm and encoding, are configured on
the resource server. Ensure that these parameters match between
the Authorization Server and the resource server.

The resource server verifies the token signature using the Authorization
Server's public key, exposed through its `/jwks` endpoint. Make sure
the signature algorithms match between both servers. Finally, introspection
token claims are verified to adhere to good  practices for handling JWTs,
including checks on issuer, audience, and expiration time.

The introspection token contains a subject (`sub`). The resource server uses
this subject to retrieve the requested database user, compatible
with both pairwise and public subjects.

Important:

Agent Connect does not follow RFC 7662 but uses a draft RFC that adds security
(signing/encryption) to the initial specification. Refer to the "References"
section for more information.

References:

The initial RFC describing token introspection is RFC 7662 "OAuth 2.0 Token
Introspection". However, this RFC specifies that the introspection
response is a plain JSON object.

In eGovernment applications, our resource server requires stronger assurance
that the Authorization Server issued the token introspection response.

France Connect's team implemented a stronger version of the spec, returning
a signed and encrypted token  introspection response. This version is still
a draft, available under:

"draft-ietf-oauth-jwt-introspection-response".
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash 9c05167d80 (backend) introduce an authorization server client
In OAuth 2.0, the Authorization Server is equivalent to the OIDC provider.

The Authorization Server exposes endpoints for token introspection and JWKS.
I’ve created a client to easily interact with the Authorization Server,
while doing the token introspection in our resource server.

Token introspection will be explained in upcoming commits.

The current OIDC library used in the project doesn’t offer token introspection,
leading to redundancy in the code handling some OIDC/OAuth2 flows.

This overlap makes the code bulky. My goal is to quickly deliver a working
PoC for the resource server, with plans to refactor in the longer run.

Please feel free to provide feedback on the class design.
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash 21371dbd1b (backend) add a '/jwks' endpoint
Introduce a new endpoint, /jwks, which returns a JSON Web Key Set (JWKS).
This set of public crypto keys will be used by external parties to encrypt
data intended for our backend. In the context of the resource server, this key
will be used by the authorization server to encrypt the introspection response.

The current implementation exposes a single public key, with the private key
configurable in the app settings. The private key is represented as a string.
For enhanced security, we might prefer to store this data in a .pem file
excluded from version control.

A few parameters for this key, such as its type and encoding, are configurable
in the settings.

A critique of the current design is its lack of extensibility.
If we decide to offer more than one encryption method, this view will require
refactoring.

Additionally, the current implementation is tightly coupled with joserfc.

This lays the foundation for further improvements.

Please note, this endpoint only public components of the key, there is no
chance for any secret leaking.
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash b40aefc505 ✏️(backend) fix minor typo
Found and fixed a minor typo. Nit-picking!
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash 591b3eedff 🏗️(backend) create a new python package for the resource server
Encapsulate all Resource Server (RS) sources in a dedicated python package.

Resource server belongs to the Oauth2 ecosystem, please find informations
here https://www.oauth.com/oauth2-servers/the-resource-server/
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash 09cb7ff6f1 (backend) add a JOSE dependency
We will add a JWKs endpoint to the application
and manipulate signed/encrypted Json Web Token (JWT).

Project lacks tooling for JSON Object Signing and Encryption (JOSE)
manipulations. After a quick benchmark, 'joserfc' has been chosen
as the dependency to add.

joserfc is a Python library that provides a comprehensive
implementation of several essential JOSE standards.

Please find the benchmark:

- Cryptography: Although using only cryptography is feasible, its
  interface/API is not as user-friendly.

- pyjwt: While pyjwt is popular, it lacks support for JWK and JWE objects,
  which are essential for the requirements.

- python-jose: The latest release of python-jose was in 2021, and the
  project seems less active compared to other alternatives.

- Authlib: Authlib is the second most popular library after pyjwt and seems
  modern with an active community. However, the parts relevant to the use case
  were extracted into a relatively new package named joserfc.

- joserfc: Although joserfc has fewer stars compared to Authlib, it was
  extracted from Authlib, which has more than 4k stars, indicating a solid
  foundation.

While the low star count of joserfc might raise concerns about its stability, it
is believed to be worth considering its addition. Adding Authlib and refactoring
later, once they finish migrating to joserfc, is also a possibility
2024-08-29 11:39:08 +02:00
lebaudantoineandaleb_the_flash c534048e97 🔧(compose) stop forcing platform for Keycloak PostgreSQL image
Forcing `platform: linux/amd64` for the PostgreSQL image causes compatibility
issues and performance degradation on Mac ARM chips (M1/M2). Removing the
platform specification allows Docker to select the appropriate architecture
automatically, ensuring better performance and compatibility.
2024-06-03 13:56:28 +02:00
Lebaud Antoineandaleb_the_flash 087bbf74f6 🔧(helm) setup logout flow from Agent Connect
Add the relevant environment configurations to make sure the backend
in dev and staging environments log out the user from Agent Connect.
2024-05-31 12:14:58 +02:00
Lebaud Antoineandaleb_the_flash 63a875bd5b ♻️(frontend) redirect the user agent to the logout endpoint
Recent updates in the backend views now requires the user agent to be
redirected to the logout endpoint.

The logout endpoint should initiate the logout flow with the OIDC provider,
by redirecting the user to the OIDC provider domain.

Thus, OIDC provider session cookie should be cleared.

E2E tests should be improved later on, when the CI and the development env
use Agent Connect integration environment. The current logout is not working
with the Keycloack configuration.
2024-05-31 12:14:58 +02:00
Lebaud Antoineandaleb_the_flash 7a26f377e3 (backend) support Agent Connect Logout flow
The default Logout view provided by Mozilla Django OIDC is not suitable
for the Agent Connect Logout flow.

Previously, when a user was logging-out, only its Django session was ended.
However, its session in the OIDC provider was still active.

Agent Connect implements a 'session/end' endpoint, that allows services to
end user session when they logout.

Agent Connect logout triggers cannot work with the default views implemented
by the dependency Mozilla Django OIDC. In their implementation, they decided
to end Django Session before redirecting to the OIDC provider.

The Django session needs to be retained during the logout process.

An OIDC state is saved to the request session, pass to Agent Connect Logout
endpoint, and verified when the backend receives the Logout callback from Agent
Connect. It seems to follow OIDC specifications.

If for any reason, the Logout flow cannot be initiated with Agent Connect,
(missing ID token in cache, unauthenticated user, etc), the user is redirected
to the final URL, without interacting with Agent Connect.
2024-05-31 12:14:58 +02:00
Lebaud Antoineandaleb_the_flash 05d9a09d63 🚚(backend) create a dedicated authentication package
Prepare adding advanced authentication features. Create a dedicated
authentication Python package within the core app.

This code organization will be more extensible.
2024-05-31 12:14:58 +02:00
Lebaud Antoineandaleb_the_flash 2f1805b721 🩹(backend) address linter flakiness on Email tests
Pylint was randomly failing due to a warning while unpacking emails.
The W0632 (Possible unbalanced tuple unpacking) was triggered.

Replace tuple unpacking by an explicitly accessing the first element of
the array using index.
2024-04-08 15:35:12 +02:00
Lebaud Antoineandaleb_the_flash 54386fcdd3 🩹(backend) address test flakiness while sorting Team accesses
Previously, there was a difference between Django's `order_by`
behavior and Python's `sorted` function, leading to test failures
under specific conditions. For example, entries such as 'Jose Smith'
and 'Joseph Walker' were not consistently sorted in the same order
between the two methods.

To resolve this issue, we've ensured that sorting the expected
results in the TeamAccess tests are both case-insensitive and
space-insensitive. This adjustment fix tests flakiness
2024-04-08 15:07:58 +02:00
Lebaud Antoineandaleb_the_flash 9ec7eddaed (frontend) add logout button
Rework the header based on latest Johann's design, which introduced a
dropdown menu to mange user account.

In this menu, you can find a logout button, which ends up the backend
session by calling the logout endpoint. Please that automatic redirection
when receiving the backend response were disabled. We handle it in our
custom hook, which reload the page.

Has the session cookie have been cleared, on reloading the page, a new
loggin flow is initiated, and the user is redirected to the OIDC provider.

Please note, the homepage design/organization is still under discussion, I
prefered to ship a first increment. The logout feature will be quite useful
in staging to play and test our UI.
2024-04-04 14:52:53 +02:00
Lebaud Antoineandaleb_the_flash 7db2faa072 🍱(frontend) rename Desk to Equipes
Update all assets related to the previous naming.
I gave some asset a more generic name, so if the app's name chang again
we won't have to rename the logo.

Linked but not assets, meta title and description were updated.
Next.js favicon was replaced by the Equipes' one.
2024-04-04 14:52:53 +02:00
Lebaud AntoineandAnthony LC c7aae51d25 🩹(test) update MemberAction props
TeamId prop was refactored to a Team object.
Update MemberAction component's tests.
2024-04-04 12:13:00 +02:00
Lebaud Antoineandaleb_the_flash e20960e3e1 💚(ci) update Github Actions using Node.js 16
Github Actions are transitioning from Node 16 to Node 20. Make sure we use
latest Github Actions versions to clean any deprecation warnings.

The migration is upcoming.
2024-04-04 10:33:20 +02:00
Lebaud Antoineandaleb_the_flash 5ed05b96a5 🩹(frontend) disable submission button while a request is pending
If any request is taking longer than expected, the user could interact with
the frontend, thinking the previous submission was not taken into account,
and would re-submit a request.

It happened to me while sending an invitation. Replaying request can either
lead to inconsistencies in db for the user, or to errors in requests' response.

I propose to disable all interactive button while submitting a request.
It's good enough for this actual sprint, these types of interactivity issues
could be improved later on.
2024-04-02 15:07:59 +02:00
Lebaud Antoineandaleb_the_flash 97cec8901c 📱(frontend) enhance team info style to avoid layout shift
On small screens, padding and alignment were causing texts to render wrapped.
It might be a personal choice, but I decided to give more space to the text,
thus avoiding text to wrap and ending up in increasing team info's height.

This issue arises when closing / opening the panel menu.
2024-03-29 15:32:52 +01:00
Lebaud Antoineandaleb_the_flash e8aba29a68 (frontend) make the team pannel closable
Team panel was quite wide, and took too much space on small screens.
Johann decided to make it closable. Thus, user that needs to navigate quickly
between their team can open it, use it and then close it.

This animation is a first draft, and should be improved later on. Also, some
accessibility issues might ariase, I have ignored them in this first draft.
2024-03-29 15:32:52 +01:00
Lebaud Antoineandaleb_the_flash ebaa1360e7 🍱(frontend) update icon button 'add team' in teams panel
Johann recently changed the icon use by the 'add team' button. He preferred
having a square one to contrast more with the 'collapse menu' icon that will
be added later on.
2024-03-29 15:32:52 +01:00
Lebaud Antoineandaleb_the_flash 6de24d973b 🔇(helm) silence some Django system checks
Django logs some security warnings we can ignored when deploying over K8s.
Inspired by fun project, I added the Django setting SILENCED_SYSTEM_CHECKS,
and silenced the two that were logging a lot of warning.
2024-03-27 12:14:36 +01:00
Lebaud Antoineandaleb_the_flash 04c107cfdb 🐛(helm) enable SSL when sending email
Email settings were wrongly configured. It led to unsent email and timeout
response from the backend server.

I forgot to enable the SSL while using the Email service from scalingo.
2024-03-27 12:14:36 +01:00
Lebaud Antoineandaleb_the_flash cbfc67f010 🔒️(helmfile) generate Django secret key
Generate a proper Django secret key ready for production,
using the provided get_random_secret_key() function.

Store its value in a k8s secret. I generated two values one for
dev and one for staging.

Previous values were triggering security logs.
2024-03-27 12:14:36 +01:00
Lebaud Antoineandaleb_the_flash cc35757c9e 🚧(frontend) add applications menu PoC
Based on works from @manuhabitela, introduce a PoC of the future component.
ApplicationsMenu component is still under construction.

This code was committed for the Wednesday 26th demo, to showcase our future
works. This Next.js integration could be improved, and will for sure!
Don't blame me.
2024-03-26 22:49:57 +01:00
Lebaud Antoineandaleb_the_flash a1065031ee (frontend) sort team's members
We are displaying all team's members in a datagrid. This propose to enable
sorting on columns, to easily find members.

Please note that few issues were faced when activating the sorting on the
Cunningham components. First, custom columns can not be sorted (yet), a PR
has been merged on Cunningham's side. We're waiting for the next release.

Second, when sorting data rows, if any of the column has some null values,
the datagrid sorting state becomes inconsistent. Thx @AntoLC for spotting the
issue. It's work in progress on Cunningham's side to fix the issue.

Finally, Cunningham export only the SortModel type, which is an array, and
doesn't export its items' type. I might have miss something but it feels weird
to redefine its items type.

Columns wiggle on sorting, because they data is set to undefined while fetching
the next batch. it's visually weird, but not a major pain.
Next release of Cunningham will allow us to set the column to a fixed size.
2024-03-26 22:15:18 +01:00
Lebaud Antoineandaleb_the_flash 2345250c4f 🚑️(staging) fix 404 errors
Recent changes on the staging cluster created a regression.
The ingress className needs to be specified.
2024-03-26 16:39:48 +01:00
Lebaud Antoineandaleb_the_flash da081b9887 🔧(renovate) open pull request with a default noChangeLog label
Discussed with @sampaccoud, Renovate PR do not necessitate ChangeLog updates
Our CI system requires a 'noChangeLog' label or an updated ChangeLog. Currently,
we manually add the label for each Renovate PR.

To improve DX, we configured Renovate to apply the label automatically.
2024-03-25 17:59:26 +01:00
Lebaud Antoineandaleb_the_flash f9fde490e8 🚀(smtp) update mail server configurations in staging
Update staging configuration, so they can use the outscale mail
gateway as recommended by @rouja.
2024-03-22 13:42:22 +01:00
Lebaud Antoineandaleb_the_flash 1b3869c1e9 🌐(backend) generate traductions
With the recent addition of mails' templates, Django traduction files
needed to be updated.

It seems that recents backend changes were not reflected into the
Django traduction file. Fixed them, and add traductions related to
the invitation email.

Last revision was made on 2024-01-01
2024-03-22 13:42:22 +01:00
Lebaud Antoineandaleb_the_flash f6d5f737f4 💚(ci) download mails templates when testing back
build-mails job builds mails Django templates but was not persisting its
output. This steps was present in Joanie CI. It might have been removed,
when converting Circle CI worflows to Github Actions.

Artifacts are passed between build-mails and test-back jobs. test-back
job has now a dependency to  build-mails.
2024-03-22 13:42:22 +01:00
Lebaud Antoineandaleb_the_flash 522914b47a (backend) email invitation to new users
When generating an Invitation object within the database, our intention
is to promptly notify the user via email. We send them an invitation
to join Desk.

This code is inspired by Joanie successful order flow.

Johann's design was missing a link to Desk, I simply added a button which
redirect to the staging url. This url is hardcoded, we should refactor it
when we will deploy Desk in pre-prod or prod environments.

Johann's design relied on Marianne font. I implemented a simpler version,
which uses a google font. That's not important for MVP.

Look and feel of this first invitation template is enough to make our PoC
functionnal, which is the more important.
2024-03-22 13:42:22 +01:00
Lebaud Antoineandaleb_the_flash 1919dce3a9 🧑‍💻(views) render email's template
THis feature is inspired by Joanie. Add two new urls to render Emails
HTML and Text templates.

Developpers can render the email template they are working on. When necessary,
run make mails-build, and reload `_debug__/mail/hello_html`, it will re-render
the updated email template.

Also, I have copy/pasted one template extra tags from Joanie, which loads
bas64 string from static images. This code is necessary to render the dummy
template `hello.html`.
2024-03-22 13:42:22 +01:00
Lebaud Antoineandaleb_the_flash 0141aa220f 🎨(models) extract invitation converter in a proper method
Improved code readability, by extracting this well-scoped unit of
logic in a dedicated method. Also, rename active_invitations to match
'valid' vocabulary used elsewhere in the doc. If no valid invitation
exists, early return to avoid nesting.
2024-03-22 13:31:24 +01:00
Lebaud Antoineandaleb_the_flash 97752e1d5f 🩹(factory) handle email uniqueness
When generating a batch of users using Faker, there's a possibility of
generating multiple users with the same email address. This breaches
the uniqueness constraint set on the email field, leading to flaky
tests that may fail when random behavior coincides unfavorably.

Implemented a method inspired by Identity's model to ensure unique
email addresses when creating user batches with Faker.
Updated relevant tests for improved stability.
2024-03-22 08:28:30 +01:00
Lebaud Antoineandaleb_the_flash 99cee241f9 (api) support TeamAccess ordering on user-based fields
Important ordering fields for TeamAccess depend on user's
identities data. User and identities has a one-to-many relationship,
which forced us to prefetch the user-related data when listing
team's accesses.

Prefetch get data from the database using two SQL queries, and
join data in Python. User's data were not available in the first
SQL query.

Without annotating the query set with user main identities data,
we could not use default OrderingFilter backend code, which order_by()
the queryset.
2024-03-22 08:28:30 +01:00
Lebaud Antoineandaleb_the_flash 6de0d013c3 (api) support TeamAccess ordering on their role
Enhance list capabilities, by adding the OrderingFilter as filter backend,
to the TeamAccess viewset.

API response can be ordered by TeamAccess role. More supported ordering
fields will be supported later on.
2024-03-22 08:28:30 +01:00
Lebaud Antoineandaleb_the_flash 1de743e18a (pagination) add few tests on page's size
We created a custom Pagination class, were max_page_size is overriden.
I decided to add bare minimum tests to make sure we can set the maximum
page size using the 'page_size' query parameter.
2024-03-22 08:28:30 +01:00
Lebaud Antoineandaleb_the_flash 756867da19 🔥(pagination) remove unused ordering field
Our Pagination class inherits from the PageNumberPagination Django class.
However, this base class as not ordering attribute. Thus, setting a
default value wont have any effect on the code.

Why did we end up passing a value to this non-existing attribute? Becasue
we copy/pasted some code sources from Joanie, and Joanie also has this
attribute set to a default value.

If you take a look at DRF pagination style documentation, the only three
attributes they set on the child class are 'page_size', 'max_page_size'
'page_size_query_param'. 'ordering' is not mentionned in the attributes
you may override. However, the CursorPagination class offers the latter
attribute, which may explain why we did end up setting this non-existing
attribute in Joanie.
2024-03-22 08:28:30 +01:00
Lebaud Antoineandaleb_the_flash d15adb4421 🐛(helm) fix wrongly named ingress
Admin ingress has been partially renamed to ingressAdmin.
I forgot to update helmfile values. Fixed them.
2024-03-21 17:51:09 +01:00
Lebaud Antoineandaleb_the_flash bdddbb84a5 📝(helm) update chart's README
Run the ./generate-readme.sh script to keep the README file
up to date with the values.yaml.
2024-03-21 10:49:58 +01:00
Lebaud Antoineandaleb_the_flash de4551ab30 🚀(helm) support Django Admin pages in ingress paths
Based on @rouja reco, I added a dedicated ingress to serve Django Admin
pages and Django statics. The admin route will be secured by the oauth proxy.

I simply copy/pasted the first ingress template, and adapted it.
2024-03-21 10:49:58 +01:00
Lebaud Antoineandaleb_the_flash e8a241adbc 🔧(helm) enable liveness and readiness probes on backend deployment
Enable the probes to track liveness and readiness of any backend pods.
Helm values were updated to enable the relevant configuration.
2024-03-21 10:49:58 +01:00
Lebaud Antoineandaleb_the_flash b3b1343796 🚀(helm) add a Redis cache service
This commit is working in progress. I have added an extra chart to take
benefits of the Redis operator developed by Indie hoster.

When using the dev environment, I used bitnami redis chart to deploy
a Redis service with authentication disable.
2024-03-21 10:49:58 +01:00
Lebaud Antoineandaleb_the_flash d49cc11ef1 🩹(helm) rename mismatching environment variable
CSRF trusted origins are set using an environment variable. The env
value was wrongly name to CORS_ALLOWED_ORIGINS, which doesn't exist
in our Django configurations. I fixed this minor issue.
2024-03-21 10:49:58 +01:00
Lebaud Antoineandaleb_the_flash 28adf987f7 🔐(helm) add OIDC secrets for dev environment
Set OIDC secrets for the dev environment. Please note that we use different
secrets between dev and staging. Why? Benoit created two client id, thus we
could easily tests Agent Connect feature from the local host and the staging
one.

The local host is desk.127.0.0.1.nip.io. If this value change at any time,
please consider asking Benoit to update the host value linked to the dev
client id.
2024-03-21 10:49:58 +01:00
Lebaud Antoineandaleb_the_flash a8a001e1e4 🚀(helm) build a minimalistic dev Helmfile
Please note that this Helmfile is uncomplete, it lacks services as
redis, celery, mail ... which are declared in the Docker Compose file
but not yet used in development and production images.

Thus, to run the Desk Helm chart, we only add a postgres database to run the
Django backend server, and apply migrations.

For now, this Helmfile is quite hard to test in dev environment, because the
frontend redirects automatically to the SSO login page. We cannot really
assess if backend and frontend are working properly. We might adjust some
configurations after the first deployment in stagging.

(We are a bit in rush, to respect the current sprint deadline.)

Development values points https://desk.127.0.0.1.nip.io URL. Please note that
the frontend image for now has been built with this URL for the backend address.
Meaning that we either need to rebuild and publish a frontend image with the
staging URL when deploying the project, or enhance our frontend image, to pass
the backend URL at runtime.
2024-03-21 10:49:58 +01:00
Lebaud Antoineandaleb_the_flash bbd8e1b48d 🚀(helm) write desk Helm chart
First, thanks a LOT @rouja for your help along the way.
This commit propose a first draft of Helm chart to prepare deployment.
It follows Plane's Helm Chart, hosted on the shared team repo,
please https://github.com/numerique-gouv/helm-charts, PR #11

It offers advanced templating function under _helpers.tpl, an auto-generated
README file when running ./generate-readme.sh, and a clear files structure.

The chart itself is quite simple. We have two deployments, one for the
frontend and one for the backend. Both need a dedicated service, which are
exposed using a common ingress. Frontend is accessible from the / path and
backend's from /api path.

Please note, we added a backend job to migrate the database when deploying
backend's pods. This job should be auto-cleaning itself 100s after it completes
to avoid any error when syncing helm.

values.yaml file is quite pristine, all common env variables will be set
in helmfile configuration.

Deploying frontend static files through kubernetes is temporary, we plan to
either remplace it by an external CDN or use minio to host static output in
a S3 bucket within the cluster.
2024-03-21 10:49:58 +01:00
Lebaud Antoineandaleb_the_flash e4a6b33366 🐛(docker) switch CMD form from Shell to Exec
`backend-development` and `backend-production` CMD syntaxes were
using a Shell Form. Shell form prevented Unix signals from reaching
our container correctly, such as SIGTERM. Also, the shell process
ends up being the PID 1, instead of our Python scripts.

Docker recommends to use the exec form whenever possible.
2024-03-20 09:31:19 +01:00
Lebaud Antoineandaleb_the_flash 44b5999df8 🔧(backend) configure RedisCache in production settings
In development, sessions are saved in local memory. It's working well,
however it doesn't adapt to a kubernetized setup. Several pods need
to access the current sessions, which need to be stored in a single
source of truth.

With a local memory cache, pods cannot read session saved in other pods.
We end up returning 401 errors, because we cannot authenticate the user.

I preferred setting up a proper cache than storing sessions in database,
because in the long run it would be a performance bottleneck. Cache will
decrease data access latency when reading current sessions.

I added a Redis cache backend to the production settings. Sessions would
be persisted to Redis. In K8s, a Redis operator will make sure the cached
data are not lost.

Two new dependencies were added, redis and django-redis.

I followed the installation guide of django-redis dependency. These
setting were tested deploying the app to a local K8s cluster.
2024-03-19 16:57:27 +01:00
Lebaud Antoineandaleb_the_flash 8e76a0ee79 🔧(frontend) update production value for the API_URL env var
For now, the env variable should point to the only deployed environment,
staging. It'll allow @rouja deploying for the first time our project.
2024-03-15 16:32:58 +01:00
Lebaud Antoineandaleb_the_flash a2ff33663b 🚚(docker) make images naming consistent
It was quite confusing having development, production and
frontend images' names in the same Docker file. New comers
to the project would have some difficuluties when
differentiating frontend from backend images.

Try to make these naming more explicit and consistent.
Thanks @rouja for your recommendation.
2024-03-15 16:32:58 +01:00
Lebaud Antoineandaleb_the_flash 78459df962 🐛(docker) build Docker images with an unprivileged user
This is a major issue. Docker Images were built and published with a
root user in the CI.

if a user manages to break out of the application running as root in the
container, he may gain root user access on host. In addition, configuring
container to user unprivileged is the best way yo prevent privilege
escalation attacks.

We mitigated this issue by creating a new environment variable DOCKER_USER.
DOCKER_USER is set with id -u and id -g outputs. Then, it is passed as a
build-args when running docker/build-push-action steps.
2024-03-15 16:32:58 +01:00
Lebaud Antoineandaleb_the_flash 4579e668b6 ️(docker) add frontend dependencies to .dockerignore
Ignore frontend dependencies when coping frontend sources to build
the frontend Docker image. It would improve a bit performances locally,
when building the frontend image.
2024-03-15 16:32:58 +01:00
Lebaud Antoineandaleb_the_flash 6ee39a01af 🎨(env) add missing newline at EOF
Found wrongly formatted files, fixed them.
2024-03-15 16:32:58 +01:00
Lebaud Antoineandaleb_the_flash 3378d4b892 👷(frontend) push frontend image to DockerHub
Build and push the frontend image to DockerHub. Backend an Frontend
images will be stored in separate repos: people-backend and people-frontend.

It will be cleaner than managing all images in a single repo and creating
tags to discriminate frontend and backend images.

CI code is not factorized between jobs. Frontend and backend jobs could be
a bit factorized. Hovewer it might be a bit premature, and I prefer having
them decoupled for now. @rouja suggested to introduce a custom github actions
to avoid maintaining the same logic accross different repo.

Please not as the images are built from the same Dockerfile, it's important
to precise the right target.
2024-03-15 16:32:58 +01:00
Lebaud Antoineandaleb_the_flash c40f656622 ⬆️(project) upgrade mail-builder Node Image
Updated to Node Image version 20 to align with the frontend image. It will
save us having two different Node versions in the same docker file, and
should not impact mail-builder.
2024-03-15 16:32:58 +01:00
Lebaud Antoineandaleb_the_flash 1a3b396230 (frontend) introduce frontend Docker Image
To facilitate deployment on Kubernetes, we've introduced a Docker image for the
frontend. The Next.js project is built, and its static output is served using an
Nginx reverse proxy.

Since DevOps lacks a certified cold storage solution (e.g., S3) for serving
static files, we've decided to containerize the frontend as a quick workaround
for deploying staging environments.

Please note this Docker Image is WIP. One of the main issue still not resolved
concerns environment variables, which are only available when building the
Docker Image. Thus, having different environment variables values between
environment (dev, pre-prod, prod) will require us to build several frontend
images, and tag them with the appropriate target environment.

The `.env.production` values are not the final ones. For now, they were set to
dev values. It allows us to test the frontend image with the development setup.

Important: The frontend image is built-on top of an unprivileged Nginx image,
which exposes by default port 8080 instead of 80 for classic Nginx image.
You can find more info https://github.com/nginxinc/docker-nginx-unprivileged.

The Docker Compose Nginx service is used to proxy OIDC requests to keycloak,
in order to share the same host when initiating an OIDC flow, from outside and
inside docker virtual network.

All Nginx configurations related to serve frontend static build were moved to a
newly created conf file under src/frontend/apps/desk. When starting the frontend
image, we desire to start the minimum Nignx config required to serve frontend
statics.
2024-03-15 16:32:58 +01:00
Lebaud Antoineandaleb_the_flash 7d65de1938 (backend) search user on her email and name
Compute Trigram similarity on user's name, and sum it up
with existing one based on user's email.

This approach is inspired by Contact search feature, which
computes a Trigram similarity score on first name and last
name, to sum up their scores.

With a similarity score influenced by both email and name,
API results would reflect both email and name user's attributes.

As we sum up similarities, I increased the similarity threshold.
Its value is empirical, and was finetuned to avoid breaking
existing tests. Please note, the updated value is closer to the
threshold used to search contacts.

Email or Name can be None. Summing two similarity scores with
one of them None, results in a None total score. To mitigate
this issue, I added a default empty string value, to replace
None values. Thus, the similarity score on this default empty
string value is equal to 0 and not to None anymore.
2024-03-11 20:23:05 +01:00
Lebaud Antoineandaleb_the_flash b2d68df646 (backend) mock identities' name when searching a user
When testing user search, we generated few identities
with mocked emails.

Name attribute was introduced on Identity model. Currently
names are freely and randomly generated by the factory.

To make this mocked data more realist, mock also identities'
names to match their email.

It should not break existing tests, and will make them more
predictable when introducing advanced search features.
2024-03-11 20:23:05 +01:00
Lebaud Antoineandaleb_the_flash b416c57bbe 🩹(frontend) fix layout overflow in Team info
Few minor layout issues were fixed.

First display label and dates inline, so they wrap nicely
when screen's size decreases. It also fixes the text overflow
when the screen's size is tiny.

Then, align screen with the Figma design, where items are
justified on the left of the Team info component.
2024-03-11 12:17:17 +01:00
Lebaud Antoineandaleb_the_flash b5ce19a28e 📝(backend) clarify how team accesses are queried
Break copy/pasted comment from Joanie in several inline
comments, that are more specific and easy to read.

Hopefully, it will help future myself understanding this
queryset and explaining it.
2024-03-07 19:55:53 +01:00
Lebaud Antoineandaleb_the_flash 163f987132 🐛(backend) fix team accesses abilities
To compute accesses's abilities, we need to determine
which is the user's role in the team.

We opted for a subquery, which retrieves the user's role
within the team and annotate queryset's results.

The current subquery was broken, and retrieved other
users than the request's user. It led to compute accesses'
abilities based on a randomly picked user.
2024-03-07 19:55:53 +01:00
Lebaud Antoineandaleb_the_flash e9482a985f (backend) enhance tests when listing team accesses
Abilities on team accesses are computed based on request user role.
Thus, members' roles in relation with user's role matters a lot, to
ensure the abilities were correctly computed.

Complexified the test that lists team accesses while being authenticated.
More members are added to the team with privileged roles. The user
is added last to the less with the less privileged role, "member".

Order matters, because when computing the sub query to determine
user's role within the team, code use the first result value to set the
role to compute abilities.
2024-03-07 19:55:53 +01:00
Lebaud Antoineandaleb_the_flash 43d802a73b 🎨(backend) early return in User factory
Avoid unnecessary nesting when code can early return.
Also, rename "item" to a more explicit name "user_entry".

it's very nit-picking, sorry.
2024-03-07 11:42:34 +01:00
Lebaud Antoineandaleb_the_flash b4e4940fd7 🚨(backend) update Ruff config to suppress deprecation warning
When running make ruff-check, a warning informs the user that
some config are deprecated, and gives her the step to migrate.

This warning appears after Ruff released its v0.2.0.
Fix it, by keeping our pyproject.toml up to date.
2024-03-07 11:31:31 +01:00
Lebaud Antoineandaleb_the_flash 5ec0dcf206 🚨(backend) follow Ruff 2024.2 style introduced in v0.3.0
We recently updated Ruff from 0.2.2 to v0.3, which introduced
Ruff 2024.2 style. This new style updated Ruff formatter's behavior,
making our make lint command fails.

Ruff 2024.2 style add a blank line after the module docstring.
Please take a look at Ruff ChangeLog to get more info.
2024-03-07 11:31:31 +01:00
Lebaud Antoineandaleb_the_flash 26fbe9fbe7 ✏️(project) fix minor typos
Found typos and fixed them.
2024-02-22 11:59:36 +01:00
Lebaud Antoineandaleb_the_flash 4cacfd3a45 ♻️(frontend) switch to Authorization Code flow
Instead of interacting with Keycloak, the frontend navigate to the
/authenticate endpoint, which starts the Authorization code flow.

When the flow is done, the backend redirect back to the SPA,
passing a session cookie and a csrf cookie.

Done:
- Query GET user/me to determine if user is authenticated yet
- Remove Keycloak js dependency, as all the OIDC logic is handled by the backend
- Store user's data instead of the JWT token
2024-02-22 11:59:36 +01:00
Lebaud Antoineandaleb_the_flash 38c4d33791 (backend) support Authorization code flow
Integrate 'mozilla-django-oidc' dependency, to support
Authorization Code flow, which is required by Agent Connect.

Thus, we provide a secure back channel OIDC flow, and return
to the client only a session cookie.

Done:
- Replace JWT authentication by Session based authentication in DRF
- Update Django settings to make OIDC configurations easily editable
- Add 'mozilla-django-oidc' routes to our router
- Implement a custom Django Authentication class to adapt
'mozilla-django-oidc' to our needs

'mozilla-django-oidc' routes added are:
- /authenticate
- /callback (the redirect_uri called back by the Idp)
- /logout
2024-02-22 11:59:36 +01:00
Lebaud Antoineandaleb_the_flash ec28c28d47 (backend) drop JWT authentication in API tests
Force login to bypass authorization checks when necessary.

Note: Generating a session cookie through OIDC flow
is not supported while testing our API.
2024-02-22 11:59:36 +01:00
Lebaud Antoineandaleb_the_flash 927d0e5a22 🔧(project) proxy Keycloak with nginx
Backend and Frontend send requests to Keycloak through Nginx.

Thus, all requests from frontend and backend shared a same host
when received by Keycloak.

Otherwise, the flow is initiated from http://localhost:8080. When the Backend
calls token endpoint from Keycloak container at http://keycloak:8080,
the JWT token issuer and sender are mismatching.
2024-02-22 11:59:36 +01:00
Lebaud Antoineandaleb_the_flash 699854e76b 🔧(project) configure standard OIDC flow in Keycloak
Enforce Authorization Code flow, and disable Implicit flow.

Done:
- Rename client people-front to people
- Add a client secret shared with the backend
- Add allowed redirect uris
- Disable implicit flow and enable Authorization Code flow without PCKE
- Sign userinfo endpoint to return application/jwt content
2024-02-22 11:59:36 +01:00
Lebaud Antoineandaleb_the_flash 469903c9eb ✏️(project) fix minor typos
Found typos, fixed them.
2024-02-16 16:03:52 +01:00
Lebaud Antoineandaleb_the_flash 1f1253ab21 🔧(backend) activate container liveness probes
Enabled Dockerflow Django app by activating liveness probes. The previously
unavailable routes such as `__heartbeat__` and `__lbheartbeat__` are now
accessible. New endpoints include:
* GET /__version__
* GET /__heartbeat__
* GET /__lbheartbeat__
2024-02-16 15:16:30 +01:00
Lebaud Antoineandaleb_the_flash 6620932371 🐛(project) run production image locally with docker-compose
The local deployment of the Production image through docker-compose was
failing due to issues in the Django configurations, influenced by Joanie.

The bug stemmed from a dependency on a development-specific package
(drf-spectacular-sidecar) while attempting to run the application in
production mode.

Changes Made:
- Introduced new Django settings for local demo environments.
- Uncommented the nginx configuration to address the production image
  deployment issues.
2024-02-16 15:16:30 +01:00
Lebaud Antoineandaleb_the_flash 6080af961a 🩹(backend) fix Django Admin UserAdmin page
*Broken Identity string representation
Resolving a format error in the Identity string representation caused by
potential None values in the email field. This issue was discovered when
attempting to access the User details page in the Django Admin

*Broken User creation form
The replacement of the User's username with an email led to errors in
the UserAdmin class. The base class used the 'username' field in the
'add_fieldsets' attribute. This problem was discovered while attempting to
create a new user in the Django Admin.
2024-02-15 15:54:07 +01:00
Lebaud Antoineandaleb_the_flash d1cc1942dc 🩹(backend) enhance Django Admin for Team Slug
Make Team's Slug field non-editable in the Django admin. It avoid
UX issues by preventing accidental slug overwrites during updates.
The Slug is now displayed in the teams list view.
2024-02-12 11:47:46 +01:00
Lebaud Antoineandaleb_the_flash a7d72d0fab 👷(project) streamline Docker image publishing workflow
Refactored 'Hub' CI job for clarity, using 'docker/build-push-action.'
This dedicated workflow efficiently manages image releases on push tag
and main branch merges events.

'Hub' job was broken by Chat GPT translation from Circle CI.

Images are pushed to a temporary Docker Hub repository,
lasuite/people.

Duplicated 'build-docker' job was removed from people workflow.
2024-02-12 11:37:38 +01:00
Lebaud Antoineandaleb_the_flash 46ad7435c8 🔐(project) add Docker Hub secrets
Added Docker Hub username and password, to shared secrets.
2024-02-12 11:37:38 +01:00
Lebaud Antoineandaleb_the_flash c117f67952 ✏️(project) fix minor typos
Found typos and fixed them.
2024-02-06 08:58:21 +01:00
Lebaud Antoineandaleb_the_flash c54d457fa6 🎨(project) fixed minor code formatting issues in .sops.yaml
Identified and resolved minor code formatting issues.

Updates:
* Add a newline at the end of the file
* Capitalize first names and last names of all users.
2024-02-01 13:54:18 +01:00
Lebaud Antoineandaleb_the_flash ab7d466823 🔧(project) enable renovate dependency dashboard
Enable renovate bot to open an issue with a dependency dashboard.
2024-01-29 15:09:13 +01:00
Lebaud Antoineandaleb_the_flash d5f16cddb0 🔧(project) update Renovate configuration to fix match manager issue
The current Renovate configuration is using the wrong match manager, as our
project utilizes `pyproject.toml` instead of `setup.cfg`. This commit corrects
the configuration to ensure compatibility with our project structure.
2024-01-29 13:24:17 +01:00