1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.metalava 18 19 import org.junit.Rule 20 import org.junit.Test 21 import org.junit.rules.TemporaryFolder 22 import java.io.File 23 import kotlin.test.assertEquals 24 import kotlin.test.assertTrue 25 26 class FileReadSandboxTest { 27 @get:Rule 28 var temporaryFolder = TemporaryFolder() 29 30 @Test Test sandboxnull31 fun `Test sandbox`() { 32 // Create target files. 33 val root = temporaryFolder.newFolder() 34 35 val goodFile = File(root, "goodFile").apply { createNewFile() } 36 val badFile = File(root, "badFile").apply { createNewFile() } 37 38 val goodDir = File(root, "goodDir").apply { mkdirs() } 39 val goodDirFile = File(goodDir, "file").apply { createNewFile() } 40 41 val badDir = File(root, "badDir").apply { mkdirs() } 42 val badDirFile = File(badDir, "file").apply { createNewFile() } 43 44 val subDir = File(root, "subdir").apply { mkdirs() } 45 val subSubDir = File(subDir, "subdir").apply { mkdirs() } 46 val subSubDir2 = File(subDir, "subdir2").apply { mkdirs() } 47 val subSubDirGoodFile = File(subSubDir, "good").apply { createNewFile() } 48 val subSubDirBadFile = File(subSubDir, "bad").apply { createNewFile() } 49 50 // Structure: 51 // - * Explicitly allowed 52 // - ** Implicitly allowed (parent directories of allowed paths) 53 // - @ Not allowed 54 // root ** 55 // |-goodFile * 56 // | 57 // |-badFile @ 58 // | 59 // |-goodDir * 60 // | |-goodDirFile ** 61 // | 62 // |-badDir @ 63 // | |-badDirFile @ 64 // | 65 // |-subDir ** 66 // |-subSubDir ** 67 // | |-subSubDirGoodFile * 68 // | |-subSubDirBadFile @ 69 // |-subSubDir2 @ 70 71 // Set up the sandbox. 72 FileReadSandbox.allowAccess(goodFile) 73 FileReadSandbox.allowAccess(goodDir) 74 FileReadSandbox.allowAccess(subSubDirGoodFile) 75 76 val allowedSet = mutableSetOf(root, goodFile, goodDir, goodDirFile, subDir, subSubDir, subSubDirGoodFile).map { it.absolutePath } 77 val emptySet = setOf<String>() 78 val violations = mutableSetOf<String>() 79 80 // Make sure allowed files are not in the violation list. 81 fun assertAllowedFilesNotReported() { 82 assertEquals(emptySet, violations.intersect(allowedSet)) 83 } 84 85 // Assert given files are reported as violations. 86 fun assertViolationReported(vararg files: File) { 87 val fileSet = files.map { it.absolutePath }.toSet() 88 assertEquals(fileSet, violations.intersect(fileSet)) 89 } 90 91 // Assert given files are *not* reported as violations. 92 fun assertViolationNotReported(vararg files: File) { 93 val fileSet = files.map { it.absolutePath }.toSet() 94 assertEquals(emptySet, violations.intersect(fileSet)) 95 } 96 97 val listener = object : FileReadSandbox.Listener { 98 override fun onViolation(absolutePath: String, isDirectory: Boolean) { 99 violations.add(absolutePath) 100 } 101 } 102 103 // Activate the sandbox. 104 FileReadSandbox.activate(listener) 105 try { 106 // Access "good" files, which should be allowed. 107 goodFile.readBytes() 108 subSubDirGoodFile.readBytes() 109 110 // If a file is created by metalava, then it can be read. 111 val newFile1 = File(root, "newFile1").apply { createNewFile() } 112 newFile1.readBytes() 113 114 assertAllowedFilesNotReported() 115 assertViolationNotReported(badFile, badDir, badDirFile, subSubDirBadFile) 116 117 // Access "bad" files. 118 badFile.readBytes() 119 badDirFile.readBytes() 120 121 assertAllowedFilesNotReported() 122 assertViolationReported(badFile, badDirFile) 123 assertViolationNotReported(subSubDirBadFile) 124 125 // Clear the violations, and access badDir. 126 violations.clear() 127 badDir.listFiles() 128 root.listFiles() 129 130 assertAllowedFilesNotReported() 131 assertViolationReported(badDir) 132 assertViolationNotReported(badFile, badDirFile, subSubDirBadFile) 133 134 // Check "implicitly allowed access" directories. 135 violations.clear() 136 subDir.listFiles() // Implicitly allowed. 137 subSubDir.listFiles() // Implicitly allowed. 138 subSubDir2.listFiles() // *Not* implicitly allowed. 139 subSubDirGoodFile.readBytes() 140 subSubDirBadFile.readBytes() // *Not* allowed. 141 root.listFiles() 142 143 assertAllowedFilesNotReported() 144 145 assertViolationReported(subSubDir2, subSubDirBadFile) // These are not allowed to read. 146 } finally { 147 // Deactivate the sandbox. 148 FileReadSandbox.deactivate() 149 FileReadSandbox.reset() 150 } 151 violations.clear() 152 153 // This shouldn't trigger the listener. 154 badFile.readBytes() 155 156 assertTrue(violations.isEmpty()) 157 } 158 } 159