openproject: ingress: enabled: false persistence: enabled: false s3: enabled: true auth: existingSecret: "openproject-s3-mapped" bucketName: "openproject" endpoint: "http://rook-ceph-rgw-ceph-objectstore.rook-ceph.svc:80" pathStyle: true region: "us-east-1" postgresql: bundled: false connection: host: openproject-pg-cluster-rw.openproject.svc.cluster.local port: 5432 auth: existingSecret: openproject-pg-cluster-app secretKeys: userPasswordKey: password options: sslmode: require replicaCount: 1 metrics: enabled: false extraVolumes: - name: enterprise-token configMap: name: openproject-enterprise-token defaultMode: 0644 extraVolumeMounts: - name: enterprise-token mountPath: /app/app/models/enterprise_token.rb subPath: enterprise_token.rb readOnly: true appInit: resources: requests: memory: "512Mi" limits: memory: "1Gi" extraObjects: - apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: openproject namespace: openproject spec: parentRefs: - name: traefik-gateway namespace: traefik sectionName: websecure hostnames: - openproject.noxxos.nl rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: openproject port: 8080 - apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: openproject-pg-cluster namespace: openproject spec: instances: 2 postgresql: parameters: max_connections: "100" shared_buffers: "25MB" effective_cache_size: "75MB" maintenance_work_mem: "6400kB" checkpoint_completion_target: "0.9" wal_buffers: "768kB" default_statistics_target: "100" random_page_cost: "1.1" effective_io_concurrency: "300" work_mem: "640kB" huge_pages: "off" max_wal_size: "128MB" bootstrap: initdb: database: openproject owner: openproject storage: size: 20Gi storageClass: local-path resources: requests: cpu: 100m memory: 100Mi limits: memory: 512Mi plugins: - enabled: true name: barman-cloud.cloudnative-pg.io isWALArchiver: true parameters: barmanObjectName: backup-store - apiVersion: barmancloud.cnpg.io/v1 kind: ObjectStore metadata: name: backup-store namespace: openproject spec: retentionPolicy: "30d" configuration: destinationPath: s3://cnpg-backup-openproject/ endpointURL: http://rook-ceph-rgw-ceph-objectstore.rook-ceph.svc:80 s3Credentials: accessKeyId: name: cnpg-backup key: AWS_ACCESS_KEY_ID secretAccessKey: name: cnpg-backup key: AWS_SECRET_ACCESS_KEY wal: compression: bzip2 data: compression: bzip2 immediateCheckpoint: true - apiVersion: postgresql.cnpg.io/v1 kind: ScheduledBackup metadata: name: cnpg-backup namespace: openproject spec: method: plugin immediate: true schedule: "0 45 2 * * *" # 2:45 AM daily backupOwnerReference: self cluster: name: openproject-pg-cluster pluginConfiguration: name: barman-cloud.cloudnative-pg.io - apiVersion: objectbucket.io/v1alpha1 kind: ObjectBucketClaim metadata: name: cnpg-backup namespace: openproject spec: bucketName: cnpg-backup-openproject storageClassName: ceph-bucket additionalConfig: maxSize: "50Gi" - apiVersion: objectbucket.io/v1alpha1 kind: ObjectBucketClaim metadata: name: openproject namespace: openproject spec: bucketName: openproject storageClassName: ceph-bucket additionalConfig: maxSize: "200Gi" - apiVersion: v1 kind: ServiceAccount metadata: name: openproject-s3-sync namespace: openproject - apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: openproject-s3-sync namespace: openproject rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "create", "update", "patch"] - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: openproject-s3-sync namespace: openproject subjects: - kind: ServiceAccount name: openproject-s3-sync namespace: openproject roleRef: kind: Role name: openproject-s3-sync apiGroup: rbac.authorization.k8s.io - apiVersion: batch/v1 kind: Job metadata: name: openproject-s3-sync namespace: openproject spec: template: spec: serviceAccountName: openproject-s3-sync containers: - name: sync image: bitnami/kubectl:latest command: - /bin/sh - -c - | echo "Waiting for secret openproject..." until kubectl get secret openproject -n openproject; do sleep 5; done ACCESS_KEY=$(kubectl get secret openproject -n openproject -o jsonpath='{.data.AWS_ACCESS_KEY_ID}' | base64 -d) SECRET_KEY=$(kubectl get secret openproject -n openproject -o jsonpath='{.data.AWS_SECRET_ACCESS_KEY}' | base64 -d) kubectl create secret generic openproject-s3-mapped -n openproject \ --from-literal=OPENPROJECT_FOG_CREDENTIALS_AWS__ACCESS__KEY__ID="$ACCESS_KEY" \ --from-literal=OPENPROJECT_FOG_CREDENTIALS_AWS__SECRET__ACCESS__KEY="$SECRET_KEY" \ --dry-run=client -o yaml | kubectl apply -f - restartPolicy: OnFailure - apiVersion: v1 kind: ConfigMap metadata: name: openproject-enterprise-token namespace: openproject data: enterprise_token.rb: | # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License version 3. # # OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: # Copyright (C) 2006-2013 Jean-Philippe Lang # Copyright (C) 2010-2013 the ChiliProject Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # See COPYRIGHT and LICENSE files for more details. #++ class EnterpriseToken < ApplicationRecord class << self # On the backend, features are checked only using `allows_to?`, which we can hardcode to return `true`. # On the frontend, however, it instead checks if particular strings are included in the `available_features` # Unfortunately there is no canonical variable with all the features, so we have to hardcode. # Use `rg --pcre2 -INo "(?<=allows_to\?[^:*]:|allowsTo\(')[a-z_]*" | sort -u` to generate this list: TRUE_FEATURES = %i[ allowed_action baseline_comparison board_view calculated_values conditional_highlighting custom_actions custom_field_hierarchies customize_life_cycle date_alerts define_custom_style edit_attribute_groups forbidden_action gantt_pdf_export internal_comments ldap_groups nextcloud_sso one_drive_sharepoint_file_storage placeholder_users readonly_work_packages scim_api sso_auth_providers team_planner_view time_entry_time_restrictions virus_scanning work_package_query_relation_columns work_package_sharing work_package_subject_generation ].freeze # Not all the methods here are ever actually called outside the enterprise_token.rb file itself # in upstream openproject, but I'll include all of them that can be reasonably implemented here, # just in case openproject changes in the future to start using the extra methods. def current self.new end def all_tokens [self.new] end def active_tokens [self.new] end def active_non_trial_tokens [self.new] end def active_trial_tokens [] end def active_trial_token nil end def allows_to?(feature) true end def active? true end def trial_only? false end def available_features TRUE_FEATURES end def non_trialling_features TRUE_FEATURES end def trialling_features [] end def trialling?(feature) false end def hide_banners? true end def show_banners? false end def user_limit nil end def non_trial_user_limit nil end def trial_user_limit nil end def banner_type_for(feature:) nil end def get_user_limit_of(tokens) nil end end FAR_FUTURE_DATE = Date.new(9999, 1, 1) def token_object Class.new do def id "lmao" end def has_feature?(feature) true end def will_expire? false end def mail "admin@example.com" end def subscriber "markasoftware-free-enterprise-mode" end def company "markasoftware" end def domain "markasoftware.com" end def issued_at Time.zone.today - 1 end def starts_at Time.zone.today - 1 end def expires_at Time.zone.today + 1 end def reprieve_days nil end def reprieve_days_left 69 end def restrictions nil end def available_features EnterpriseToken.TRUE_FEATURES end def plan "markasoftware_free_enterprise_mode" end def features EnterpriseToken.TRUE_FEATURES end def version 69 end def started? true end def trial? false end def active? true end end.new end def id "lmao" end def encoded_token "oaml" end def will_expire? false end def mail "admin@example.com" end def subscriber "markasoftware-free-enterprise-mode" end def company "markasoftware" end def domain "markasoftware.com" end def issued_at Time.zone.today - 1 end def starts_at Time.zone.today - 1 end def expires_at Time.zone.today + 1 end def reprieve_days nil end def reprieve_days_left 69 end def restrictions nil end def available_features EnterpriseToken.TRUE_FEATURES end def plan "markasoftware_free_enterprise_mode" end def features EnterpriseToken.TRUE_FEATURES end def version 69 end def started? true end def trial? false end def active? true end def allows_to?(action) true end def expiring_soon? false end def in_grace_period? false end def expired?(reprieve: true) false end def statuses [] end def invalid_domain? false end def unlimited_users? true end def max_active_users nil end def sort_key [FAR_FUTURE_DATE, FAR_FUTURE_DATE] end def days_left 69 end end