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 dirctories of whitelisted 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 var allowedSet = mutableSetOf(root, goodFile, goodDir, goodDirFile, subDir, subSubDir, subSubDirGoodFile).map { it.absolutePath } 77 var emptySet = setOf<String>() 78 79 var violations = mutableSetOf<String>() 80 81 // Make sure whitelisted files are not in the violation list. 82 fun assertWhitelistedFilesNotReported() { 83 assertEquals(emptySet, violations.intersect(allowedSet)) 84 } 85 86 // Assert given files are reported as violations. 87 fun assertViolationReported(vararg files: File) { 88 val fileSet = files.map { it.absolutePath }.toSet() 89 assertEquals(fileSet, violations.intersect(fileSet)) 90 } 91 92 // Assert given files are *not* reported as violations. 93 fun assertViolationNotReported(vararg files: File) { 94 val fileSet = files.map { it.absolutePath }.toSet() 95 assertEquals(emptySet, violations.intersect(fileSet)) 96 } 97 98 val listener = object : FileReadSandbox.Listener { 99 override fun onViolation(absolutePath: String, isDirectory: Boolean) { 100 violations.add(absolutePath) 101 } 102 } 103 104 // Activate the sandbox. 105 FileReadSandbox.activate(listener) 106 try { 107 // Access "good" files, which should be allowed. 108 goodFile.readBytes() 109 subSubDirGoodFile.readBytes() 110 111 // If a file is created by metalava, then it can be read. 112 val newFile1 = File(root, "newFile1").apply { createNewFile() } 113 newFile1.readBytes() 114 115 assertWhitelistedFilesNotReported() 116 assertViolationNotReported(badFile, badDir, badDirFile, subSubDirBadFile) 117 118 // Access "bad" files. 119 badFile.readBytes() 120 badDirFile.readBytes() 121 122 assertWhitelistedFilesNotReported() 123 assertViolationReported(badFile, badDirFile) 124 assertViolationNotReported(subSubDirBadFile) 125 126 // Clear the violations, and access badDir. 127 violations.clear() 128 badDir.listFiles() 129 root.listFiles() 130 131 assertWhitelistedFilesNotReported() 132 assertViolationReported(badDir) 133 assertViolationNotReported(badFile, badDirFile, subSubDirBadFile) 134 135 // Check "implicitly allowed access" directories. 136 violations.clear() 137 subDir.listFiles() // Implicitly allowed. 138 subSubDir.listFiles() // Implicitly allowed. 139 subSubDir2.listFiles() // *Not* implicitly allowed. 140 subSubDirGoodFile.readBytes() 141 subSubDirBadFile.readBytes() // *Not* allowed. 142 root.listFiles() 143 144 assertWhitelistedFilesNotReported() 145 146 assertViolationReported(subSubDir2, subSubDirBadFile) // These are not allowed to read. 147 } finally { 148 // Deactivate the sandbox. 149 FileReadSandbox.deactivate() 150 FileReadSandbox.reset() 151 } 152 violations.clear() 153 154 // This shouldn't trigger the listener. 155 badFile.readBytes() 156 157 assertTrue(violations.isEmpty()) 158 } 159 } 160