TestConfig.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. const fs = require('node:fs')
  2. const Path = require('node:path')
  3. const crypto = require('node:crypto')
  4. const {
  5. RootKeyEncryptionKey,
  6. } = require('@overleaf/object-persistor/src/PerProjectEncryptedS3Persistor')
  7. const AWS_S3_USER_FILES_STORAGE_CLASS =
  8. process.env.AWS_S3_USER_FILES_STORAGE_CLASS
  9. // use functions to get a fresh copy, not a reference, each time
  10. function s3BaseConfig() {
  11. return {
  12. endpoint: process.env.AWS_S3_ENDPOINT,
  13. pathStyle: true,
  14. partSize: 100 * 1024 * 1024,
  15. ca: [fs.readFileSync('/certs/public.crt')],
  16. }
  17. }
  18. function s3Config() {
  19. return {
  20. key: process.env.AWS_ACCESS_KEY_ID,
  21. secret: process.env.AWS_SECRET_ACCESS_KEY,
  22. ...s3BaseConfig(),
  23. }
  24. }
  25. const S3SSECKeys = [
  26. new RootKeyEncryptionKey(
  27. crypto.generateKeySync('aes', { length: 256 }).export(),
  28. Buffer.alloc(32)
  29. ),
  30. ]
  31. function s3SSECConfig() {
  32. return {
  33. ...s3Config(),
  34. ignoreErrorsFromDEKReEncryption: false,
  35. automaticallyRotateDEKEncryption: true,
  36. dataEncryptionKeyBucketName: process.env.AWS_S3_USER_FILES_DEK_BUCKET_NAME,
  37. pathToProjectFolder(_bucketName, path) {
  38. const match = path.match(/^[a-f0-9]{24}\//)
  39. if (!match) throw new Error('not a project-folder')
  40. const [projectFolder] = match
  41. return projectFolder
  42. },
  43. async getRootKeyEncryptionKeys() {
  44. return S3SSECKeys
  45. },
  46. storageClass: {
  47. [process.env.AWS_S3_TEMPLATE_FILES_BUCKET_NAME]:
  48. AWS_S3_USER_FILES_STORAGE_CLASS,
  49. },
  50. }
  51. }
  52. function s3ConfigDefaultProviderCredentials() {
  53. return {
  54. ...s3BaseConfig(),
  55. }
  56. }
  57. function s3Stores() {
  58. return {
  59. template_files: process.env.AWS_S3_TEMPLATE_FILES_BUCKET_NAME,
  60. }
  61. }
  62. function gcsConfig() {
  63. return {
  64. endpoint: {
  65. apiEndpoint: process.env.GCS_API_ENDPOINT,
  66. projectId: 'fake',
  67. },
  68. directoryKeyRegex: /^[0-9a-fA-F]{24}\/[0-9a-fA-F]{24}/,
  69. unlockBeforeDelete: false, // fake-gcs does not support this
  70. deletedBucketSuffix: '-deleted',
  71. }
  72. }
  73. function gcsStores() {
  74. return {
  75. template_files: process.env.GCS_TEMPLATE_FILES_BUCKET_NAME,
  76. }
  77. }
  78. function fsStores() {
  79. return {
  80. template_files: Path.resolve(__dirname, '../../../template_files'),
  81. }
  82. }
  83. function fallbackStores(primaryConfig, fallbackConfig) {
  84. return {
  85. [primaryConfig.template_files]: fallbackConfig.template_files,
  86. }
  87. }
  88. const BackendSettings = {
  89. SHARD_01_FSPersistor: {
  90. backend: 'fs',
  91. stores: fsStores(),
  92. },
  93. SHARD_01_S3Persistor: {
  94. backend: 's3',
  95. s3: s3Config(),
  96. stores: s3Stores(),
  97. },
  98. SHARD_01_S3PersistorDefaultProviderCredentials: {
  99. backend: 's3',
  100. s3: s3ConfigDefaultProviderCredentials(),
  101. stores: s3Stores(),
  102. },
  103. SHARD_01_GcsPersistor: {
  104. backend: 'gcs',
  105. gcs: gcsConfig(),
  106. stores: gcsStores(),
  107. },
  108. SHARD_01_PerProjectEncryptedS3Persistor: {
  109. backend: 's3SSEC',
  110. s3SSEC: s3SSECConfig(),
  111. stores: s3Stores(),
  112. },
  113. SHARD_02_FallbackS3ToFSPersistor: {
  114. backend: 's3',
  115. s3: s3Config(),
  116. stores: s3Stores(),
  117. fallback: {
  118. backend: 'fs',
  119. buckets: fallbackStores(s3Stores(), fsStores()),
  120. },
  121. },
  122. SHARD_02_FallbackFSToS3Persistor: {
  123. backend: 'fs',
  124. s3: s3Config(),
  125. stores: fsStores(),
  126. fallback: {
  127. backend: 's3',
  128. buckets: fallbackStores(fsStores(), s3Stores()),
  129. },
  130. },
  131. SHARD_03_FallbackGcsToS3Persistor: {
  132. backend: 'gcs',
  133. gcs: gcsConfig(),
  134. stores: gcsStores(),
  135. s3: s3Config(),
  136. fallback: {
  137. backend: 's3',
  138. buckets: fallbackStores(gcsStores(), s3Stores()),
  139. },
  140. },
  141. SHARD_03_FallbackS3ToGcsPersistor: {
  142. backend: 's3',
  143. // can use the same bucket names for gcs and s3 (in tests)
  144. stores: s3Stores(),
  145. s3: s3Config(),
  146. gcs: gcsConfig(),
  147. fallback: {
  148. backend: 'gcs',
  149. buckets: fallbackStores(s3Stores(), gcsStores()),
  150. },
  151. },
  152. }
  153. function checkForUnexpectedTestFile() {
  154. const awareOfSharding = [
  155. 'FilestoreApp.js',
  156. 'FilestoreTests.js',
  157. 'TestConfig.js',
  158. 'TestHelper.js',
  159. ]
  160. for (const file of fs.readdirSync(__dirname).sort()) {
  161. if (!awareOfSharding.includes(file)) {
  162. throw new Error(
  163. `Found new test file ${file}: All tests must be aware of the SHARD_ prefix.`
  164. )
  165. }
  166. }
  167. }
  168. checkForUnexpectedTestFile()
  169. module.exports = {
  170. AWS_S3_USER_FILES_STORAGE_CLASS,
  171. BackendSettings,
  172. s3Config,
  173. s3SSECConfig,
  174. }