diff --git a/docs/drupal/automatic-updates.md b/docs/drupal/automatic-updates.md new file mode 100644 index 0000000000..68e1a3af4b --- /dev/null +++ b/docs/drupal/automatic-updates.md @@ -0,0 +1,33 @@ +# Automatic Updates + +Lagoon deploys applications in a way that is not compatible with some methods of +updating Drupal core and contrib. Lagoon expects to build immutable images and +run immutable containers. When the code of the application is changed at +runtime, it can cause any of the following problems: + +1. Containers are managed automatically by Kubernetes and may be moved, + restarted, or scaled at any time. When this happens, the original built + container image will be ran and any changes that happened at runtime are + lost. +2. Tasks and cronjobs may run with the orignal built container image and won't + have access to any updated code. +3. Updating requires write permissions to the filesystem, but it is possible to + configure an environment that forces a read-only filesystem. +4. Best practices is to deploy small containers that each do one thing. For a + typical Drupal project this means there is a `cli`, `php`, and `nginx` + container which each contain a copy of the code. Updating only one of these + containers will cause issues with code mismatches. + +The following update methods been disabled by Lagoon. + +### Drupal Automatic Updates + +The [Automatic Updates](https://www.drupal.org/project/automatic_updates) +contrib module is disabled by and it will also be disabled when it moves +into Drupal core. + +### Drush + +Using `drush pm-install` or `drush pm-update` is disabled by default as part of +the [amazeeio/drupal-integrations](https://github.com/amazeeio/drupal-integrations) +package. diff --git a/mkdocs.yml b/mkdocs.yml index a1c9a63478..6a6d68da41 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -52,6 +52,7 @@ nav: - Subfolders: drupal/subfolders.md - Integrate Drupal & Fastly: drupal/integrate-drupal-and-fastly.md - PHPUnit and PhpStorm: drupal/phpunit-and-phpstorm.md + - Automatic Updates: drupal/automatic-updates.md - WordPress: - Overview: applications/wordpress.md - Node.js-based: diff --git a/node-packages/commons/src/api.ts b/node-packages/commons/src/api.ts index 0bc1432a99..2bd3866ab0 100644 --- a/node-packages/commons/src/api.ts +++ b/node-packages/commons/src/api.ts @@ -1256,10 +1256,10 @@ export const getEnvironmentsForProject = ( } `); -export async function getOrganizationById(organization: number): Promise { +export async function getOrganizationById(id: number): Promise { const result = await graphqlapi.query(` { - organization:organizationById(organization: ${organization}) { + organization:organizationById(id: ${id}) { id name friendlyName @@ -1282,7 +1282,7 @@ export async function getOrganizationById(organization: number): Promise { `); if (!result || !result.organization) { - throw new OrganizationNotFound(`Cannot find organization ${organization}`); + throw new OrganizationNotFound(`Cannot find organization ${id}`); } return result.organization; diff --git a/services/api/src/resolvers.js b/services/api/src/resolvers.js index ebc8963a65..42ad902c79 100644 --- a/services/api/src/resolvers.js +++ b/services/api/src/resolvers.js @@ -248,6 +248,7 @@ const { updateOrganization, deleteOrganization, getOrganizationById, + getOrganizationByName, addDeployTargetToOrganization, removeDeployTargetFromOrganization, getDeployTargetsByOrganizationId, @@ -577,6 +578,7 @@ const resolvers = { deployTargetConfigsByDeployTarget: getDeployTargetConfigsByDeployTarget, allOrganizations: getAllOrganizations, organizationById: getOrganizationById, + organizationByName: getOrganizationByName, getGroupProjectOrganizationAssociation, getProjectGroupOrganizationAssociation, getEnvVariablesByProjectEnvironmentName, diff --git a/services/api/src/resources/organization/resolvers.ts b/services/api/src/resources/organization/resolvers.ts index 0954a06e38..09b50ef4f1 100644 --- a/services/api/src/resources/organization/resolvers.ts +++ b/services/api/src/resources/organization/resolvers.ts @@ -219,17 +219,17 @@ export const updateOrganization: ResolverFn = async ( }; export const getOrganizationById: ResolverFn = async ( - organization, + id, args, { sqlClientPool, hasPermission } ) => { - let oid = args.organization; - if (organization) { - oid = organization; + let oid = args.id; + if (id) { + oid = id; } await hasPermission('organization', 'view', { - organization: oid, + organization: oid, }); const rows = await query(sqlClientPool, Sql.selectOrganization(oid)); @@ -242,6 +242,30 @@ export const getOrganizationById: ResolverFn = async ( return orgResult; }; +export const getOrganizationByName: ResolverFn = async ( + name, + args, + { sqlClientPool, hasPermission } +) => { + let orgName = args.name; + if (name) { + orgName = name; + } + + const rows = await query(sqlClientPool, Sql.selectOrganizationByName(orgName)); + const orgResult = rows[0]; + + if (!orgResult) { + return null; + } + + await hasPermission('organization', 'view', { + organization: orgResult.id, + }); + + return orgResult; +}; + export const getAllOrganizations: ResolverFn = async ( root, args, diff --git a/services/api/src/resources/organization/sql.ts b/services/api/src/resources/organization/sql.ts index 273558fd62..d05fca12dd 100644 --- a/services/api/src/resources/organization/sql.ts +++ b/services/api/src/resources/organization/sql.ts @@ -74,6 +74,10 @@ export const Sql = { knex('organization') .where('id', '=', id) .toString(), + selectOrganizationByName: (name: string) => + knex('organization') + .where('name', '=', name) + .toString(), selectOrganizationProjects: (id: number) => knex('project') .where('organization', '=', id) diff --git a/services/api/src/resources/user/resolvers.ts b/services/api/src/resources/user/resolvers.ts index 2f4d42cb7e..919f06f71b 100644 --- a/services/api/src/resources/user/resolvers.ts +++ b/services/api/src/resources/user/resolvers.ts @@ -2,7 +2,6 @@ import * as R from 'ramda'; import { ResolverFn } from '../'; import { query, isPatchEmpty } from '../../util/db'; -import { logger } from '../../loggers/logger'; import { Helpers as organizationHelpers } from '../organization/helpers'; import { Sql } from './sql'; @@ -112,11 +111,21 @@ export const getAllUsers: ResolverFn = async ( export const getUserByEmail: ResolverFn = async ( _root, { email }, - { sqlClientPool, models, hasPermission }, + { sqlClientPool, models, hasPermission, keycloakGrant }, ) => { - await hasPermission('user', 'viewAll'); const user = await models.UserModel.loadUserByUsername(email); + if (keycloakGrant) { + if (keycloakGrant.access_token.content.sub == user.id) { + await hasPermission('ssh_key', 'view:user', { + users: [user.id] + }); + } else { + await hasPermission('user', 'viewAll'); + } + } else { + await hasPermission('user', 'viewAll'); + } return user; }; diff --git a/services/api/src/typeDefs.js b/services/api/src/typeDefs.js index 61e51f8bb9..5ba7036a06 100644 --- a/services/api/src/typeDefs.js +++ b/services/api/src/typeDefs.js @@ -1416,6 +1416,7 @@ const typeDefs = gql` Get an organization by its ID """ organizationById(organization: Int!): Organization + organizationByName(name: String!): Organization getGroupProjectOrganizationAssociation(input: AddGroupToOrganizationInput!): String getProjectGroupOrganizationAssociation(input: ProjectOrgGroupsInput!): String getEnvVariablesByProjectEnvironmentName(input: EnvVariableByProjectEnvironmentNameInput!): [EnvKeyValue]